From 838e77b876f942e25e3b4f8394a8c0107e31bc32 Mon Sep 17 00:00:00 2001 From: aiwe Date: Sat, 28 Mar 2020 16:40:39 +0200 Subject: [PATCH 01/21] Show tx extra size in bytes in explorer Tx extra is a vector or uint8_t which is already a one byte so we can just use this vector's size --- include/BlockchainExplorerData.h | 28 ++++++++++--------- .../BlockchainExplorerDataBuilder.cpp | 2 ++ .../BlockchainExplorerDataBuilder.h | 2 +- .../BlockchainExplorerDataSerialization.cpp | 1 + 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/BlockchainExplorerData.h b/include/BlockchainExplorerData.h index ee888bd642..47e540fe8c 100644 --- a/include/BlockchainExplorerData.h +++ b/include/BlockchainExplorerData.h @@ -1,4 +1,5 @@ // Copyright (c) 2012-2016, The CryptoNote developers, The Bytecoin developers +// Copyright (c) 2016-2020, The Karbo developers // // This file is part of Karbo. // @@ -90,33 +91,34 @@ struct TransactionExtraDetails { }; struct transactionOutputDetails2 { - TransactionOutput output; - uint64_t globalIndex; + TransactionOutput output; + uint64_t globalIndex; }; struct BaseInputDetails { - BaseInput input; - uint64_t amount; + BaseInput input; + uint64_t amount; }; struct KeyInputDetails { - KeyInput input; - uint64_t mixin; - std::vector outputs; + KeyInput input; + uint64_t mixin; + std::vector outputs; }; struct MultisignatureInputDetails { - MultisignatureInput input; - TransactionOutputReferenceDetails output; + MultisignatureInput input; + TransactionOutputReferenceDetails output; }; typedef boost::variant transactionInputDetails2; struct TransactionExtraDetails2 { - std::vector padding; - Crypto::PublicKey publicKey; - BinaryArray nonce; - BinaryArray raw; + std::vector padding; + Crypto::PublicKey publicKey; + BinaryArray nonce; + BinaryArray raw; + size_t size = 0; }; struct TransactionDetails { diff --git a/src/BlockchainExplorer/BlockchainExplorerDataBuilder.cpp b/src/BlockchainExplorer/BlockchainExplorerDataBuilder.cpp index b8acc937bf..4b3512a114 100755 --- a/src/BlockchainExplorer/BlockchainExplorerDataBuilder.cpp +++ b/src/BlockchainExplorer/BlockchainExplorerDataBuilder.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2012-2016, The CryptoNote developers, The Bytecoin developers +// Copyright (c) 2016-2020, The Karbo developers // // This file is part of Karbo. // @@ -70,6 +71,7 @@ bool BlockchainExplorerDataBuilder::fillTxExtra(const std::vector& rawE extraDetails.nonce = boost::get(field).nonce; } } + extraDetails.size = rawExtra.size(); return true; } diff --git a/src/BlockchainExplorer/BlockchainExplorerDataBuilder.h b/src/BlockchainExplorer/BlockchainExplorerDataBuilder.h index 7b4d1fcc11..ab14db3343 100755 --- a/src/BlockchainExplorer/BlockchainExplorerDataBuilder.h +++ b/src/BlockchainExplorer/BlockchainExplorerDataBuilder.h @@ -1,5 +1,5 @@ // Copyright (c) 2012-2016, The CryptoNote developers, The Bytecoin developers -// Copyright (c) 2016-2019, The Karbo developers +// Copyright (c) 2016-2020, The Karbo developers // // This file is part of Karbo. // diff --git a/src/Serialization/BlockchainExplorerDataSerialization.cpp b/src/Serialization/BlockchainExplorerDataSerialization.cpp index 3b9d750f2f..f80549fd34 100644 --- a/src/Serialization/BlockchainExplorerDataSerialization.cpp +++ b/src/Serialization/BlockchainExplorerDataSerialization.cpp @@ -137,6 +137,7 @@ void serialize(TransactionExtraDetails2& extra, ISerializer& serializer) { serializePod(extra.publicKey, "publicKey", serializer); serializer(extra.nonce, "nonce"); serializeAsBinary(extra.raw, "raw", serializer); + serializer(extra.size, "size"); } void serialize(TransactionDetails& transaction, ISerializer& serializer) { From be9c2262803eae3d857c0814f26972082bd538ef Mon Sep 17 00:00:00 2001 From: aiwe Date: Sun, 29 Mar 2020 13:24:07 +0300 Subject: [PATCH 02/21] Add a note on extra size and possible solutions --- src/CryptoNoteCore/Core.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index c059e2e004..634b5c3c73 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -318,6 +318,13 @@ bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_ return false; } + // tx extra size in bytes, uint8_t is a one byte + uint64_t extraSize = tx.extra.size(); + + // It is possible to just limit max tx extra size e.g. to prevent abuse + // (blockchain bloat) or charge fee per byte above min free size of extra, + // 0.1 Kb is enough to contain data of ordinary tx (payment id, nonce etc.) + Crypto::Hash h = NULL_HASH; getObjectHash(tx, h, blobSize); const uint64_t fee = inputs_amount - outputs_amount; From a6db9c74470fbb254a8ec74d6c52509aef3eabec Mon Sep 17 00:00:00 2001 From: aiwe Date: Tue, 31 Mar 2020 20:38:15 +0300 Subject: [PATCH 03/21] Introduce fee per byte for transaction extra (exceeding free limit of 100 bytes which is enough for basic transaction). Unlike per kB fee of Monero for the whole transaction this covers only transaction's extra field which can be used to store arbitrary additional data. And storing external data in blockchain has to be paid for. --- src/CryptoNoteConfig.h | 2 ++ src/CryptoNoteCore/Core.cpp | 14 ++++++++++---- src/CryptoNoteCore/Currency.cpp | 6 ++++++ src/CryptoNoteCore/Currency.h | 2 ++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index e66e7f746b..9bad10cb41 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -73,6 +73,8 @@ const uint64_t MAX_TX_MIXIN_SIZE_V2 = 20; const uint64_t MAX_TX_MIXIN_SIZE = MAX_TX_MIXIN_SIZE_V2; const uint32_t MIN_TX_MIXIN_V1_HEIGHT = 216245; const uint32_t MIN_TX_MIXIN_V2_HEIGHT = 216394; +const uint32_t FEE_PER_BYTE_HEIGHT = 490000; + const uint64_t MAX_TRANSACTION_SIZE_LIMIT = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_CURRENT / 4 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; const size_t DANDELION_EPOCH = 600; diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index 634b5c3c73..2a81450c8f 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -319,11 +319,11 @@ bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_ } // tx extra size in bytes, uint8_t is a one byte - uint64_t extraSize = tx.extra.size(); + uint64_t extraSize = (uint64_t)tx.extra.size(); - // It is possible to just limit max tx extra size e.g. to prevent abuse - // (blockchain bloat) or charge fee per byte above min free size of extra, - // 0.1 Kb is enough to contain data of ordinary tx (payment id, nonce etc.) + // To prevent blockchain bloat it's possible to just limit max tx extra size + // or charge fee per byte for the size exceeding free limit, 100 bytes is + // enough to contain data of the ordinary tx (public key, payment id, etc.) Crypto::Hash h = NULL_HASH; getObjectHash(tx, h, blobSize); @@ -338,6 +338,12 @@ bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_ } } else { uint64_t min = getMinimalFeeForHeight(height); + + if (height > CryptoNote::parameters::FEE_PER_BYTE_HEIGHT) { + uint64_t feePerByte = m_currency.getFeePerByte(extraSize, min); + min += feePerByte; + } + if (fee < (min - min * 20 / 100)) { logger(INFO) << "[Core] Transaction fee is not enough: " << m_currency.formatAmount(fee) << ", minimum fee: " << m_currency.formatAmount(min); enough = false; diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 46028d8068..6fa272ea78 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -425,6 +425,12 @@ namespace CryptoNote { return std::min(CryptoNote::parameters::MAXIMUM_FEE, minimumFee); } + // All that exceeds 100 bytes is charged per byte, + // the cost of one byte is 1/100 of minimal fee + uint64_t Currency::getFeePerByte(const uint64_t txExtraSize, const uint64_t minFee) const { + return txExtraSize > 100 ? minFee / 100 * (txExtraSize - 100) : 0; + } + uint64_t Currency::roundUpMinFee(uint64_t minimalFee, int digits) const { uint64_t ret(0); std::string minFeeString = formatAmount(minimalFee); diff --git a/src/CryptoNoteCore/Currency.h b/src/CryptoNoteCore/Currency.h index 2fa5e20771..b6aee1f495 100755 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -82,6 +82,8 @@ class Currency { uint64_t minimumFee() const { return m_minimumFee; } uint64_t getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t avgCurrentReward, uint64_t avgHistoricDifficulty, uint64_t avgHistoricReward, uint32_t height) const; + uint64_t getFeePerByte(const uint64_t txExtraSize, const uint64_t minFee) const; + uint64_t defaultDustThreshold() const { return m_defaultDustThreshold; } uint64_t difficultyTarget() const { return m_difficultyTarget; } From 67d5f775ee8bf73a2c1511c06362a8908d538378 Mon Sep 17 00:00:00 2001 From: aiwe Date: Wed, 1 Apr 2020 15:17:13 +0300 Subject: [PATCH 04/21] Calculate basic reward separately from calculation of final block reward and possible penalty --- src/CryptoNoteCore/Currency.cpp | 70 ++++++++++++++++++--------------- src/CryptoNoteCore/Currency.h | 1 + 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 6fa272ea78..c39242652b 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -147,44 +147,52 @@ namespace CryptoNote { } } - bool Currency::getBlockReward(uint8_t blockMajorVersion, size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins, - uint64_t fee, uint64_t& reward, int64_t& emissionChange) const { - // assert(alreadyGeneratedCoins <= m_moneySupply); - assert(m_emissionSpeedFactor > 0 && m_emissionSpeedFactor <= 8 * sizeof(uint64_t)); + uint64_t Currency::calculateReward(uint64_t alreadyGeneratedCoins) const { + // assert(alreadyGeneratedCoins <= m_moneySupply); + assert(m_emissionSpeedFactor > 0 && m_emissionSpeedFactor <= 8 * sizeof(uint64_t)); + + uint64_t baseReward = (m_moneySupply - alreadyGeneratedCoins) >> m_emissionSpeedFactor; + + // Tail emission + if (alreadyGeneratedCoins + CryptoNote::parameters::TAIL_EMISSION_REWARD >= m_moneySupply || baseReward < CryptoNote::parameters::TAIL_EMISSION_REWARD) + { + // flat rate tail emission reward, + // inflation slowly diminishing in relation to supply + //baseReward = CryptoNote::parameters::TAIL_EMISSION_REWARD; + + // Friedman's k-percent rule, + // inflation 2% of total coins in circulation per year + const uint64_t blocksInOneYear = expectedNumberOfBlocksPerDay() * 365; + uint64_t twoPercentOfEmission = static_cast(static_cast(alreadyGeneratedCoins) / 100.0 * 2.0); + baseReward = twoPercentOfEmission / blocksInOneYear; + } - // Tail emission + return baseReward; + } - uint64_t baseReward = (m_moneySupply - alreadyGeneratedCoins) >> m_emissionSpeedFactor; - if (alreadyGeneratedCoins + CryptoNote::parameters::TAIL_EMISSION_REWARD >= m_moneySupply || baseReward < CryptoNote::parameters::TAIL_EMISSION_REWARD) - { - // flat rate tail emission reward - //baseReward = CryptoNote::parameters::TAIL_EMISSION_REWARD; + bool Currency::getBlockReward(uint8_t blockMajorVersion, size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins, + uint64_t fee, uint64_t& reward, int64_t& emissionChange) const { - // Friedman's k-percent rule - // inflation 2% of total coins in circulation - const uint64_t blocksInOneYear = CryptoNote::parameters::EXPECTED_NUMBER_OF_BLOCKS_PER_DAY * 365; - uint64_t twoPercentOfEmission = static_cast(static_cast(alreadyGeneratedCoins) / 100.0 * 2.0); - baseReward = twoPercentOfEmission / blocksInOneYear; - } + uint64_t baseReward = calculateReward(alreadyGeneratedCoins); - size_t blockGrantedFullRewardZone = blockGrantedFullRewardZoneByBlockVersion(blockMajorVersion); - medianSize = std::max(medianSize, blockGrantedFullRewardZone); - if (currentBlockSize > UINT64_C(2) * medianSize) { - logger(DEBUGGING) << "Block cumulative size is too big: " << currentBlockSize << ", expected less than " << 2 * medianSize; - return false; - } + size_t blockGrantedFullRewardZone = blockGrantedFullRewardZoneByBlockVersion(blockMajorVersion); + medianSize = std::max(medianSize, blockGrantedFullRewardZone); + if (currentBlockSize > UINT64_C(2) * medianSize) { + logger(DEBUGGING) << "Block cumulative size is too big: " << currentBlockSize << ", expected less than " << 2 * medianSize; + return false; + } - uint64_t penalizedBaseReward = getPenalizedAmount(baseReward, medianSize, currentBlockSize); - uint64_t penalizedFee = blockMajorVersion >= BLOCK_MAJOR_VERSION_2 ? getPenalizedAmount(fee, medianSize, currentBlockSize) : fee; - if (cryptonoteCoinVersion() == 1) { - penalizedFee = getPenalizedAmount(fee, medianSize, currentBlockSize); - } + uint64_t penalizedBaseReward = getPenalizedAmount(baseReward, medianSize, currentBlockSize); + uint64_t penalizedFee = blockMajorVersion >= BLOCK_MAJOR_VERSION_2 ? getPenalizedAmount(fee, medianSize, currentBlockSize) : fee; + if (cryptonoteCoinVersion() == 1) { + penalizedFee = getPenalizedAmount(fee, medianSize, currentBlockSize); + } - emissionChange = penalizedBaseReward - (fee - penalizedFee); - reward = penalizedBaseReward + penalizedFee; + emissionChange = penalizedBaseReward - (fee - penalizedFee); + reward = penalizedBaseReward + penalizedFee; - return true; - } + return true; + } size_t Currency::maxBlockCumulativeSize(uint64_t height) const { assert(height <= std::numeric_limits::max() / m_maxBlockSizeGrowthSpeedNumerator); diff --git a/src/CryptoNoteCore/Currency.h b/src/CryptoNoteCore/Currency.h index b6aee1f495..94c74c4261 100755 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -143,6 +143,7 @@ class Currency { const Block& genesisBlock() const { return m_genesisBlock; } const Crypto::Hash& genesisBlockHash() const { return m_genesisBlockHash; } + uint64_t calculateReward(uint64_t alreadyGeneratedCoins) const; bool getBlockReward(uint8_t blockMajorVersion, size_t medianSize, size_t currentBlockSize, uint64_t alreadyGeneratedCoins, uint64_t fee, uint64_t& reward, int64_t& emissionChange) const; size_t maxBlockCumulativeSize(uint64_t height) const; From 8764b950594d747eaf1646e6d4aa1b08d448e453 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 2 Apr 2020 11:12:37 +0300 Subject: [PATCH 05/21] A little clarification on tail reward calc. with reference to whitepaper --- src/CryptoNoteCore/Currency.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index c39242652b..127ca8fdd0 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -159,9 +159,10 @@ namespace CryptoNote { // flat rate tail emission reward, // inflation slowly diminishing in relation to supply //baseReward = CryptoNote::parameters::TAIL_EMISSION_REWARD; - + // changed to // Friedman's k-percent rule, // inflation 2% of total coins in circulation per year + // according to Whitepaper v. 1, p. 16 (with change of 1% to 2%) const uint64_t blocksInOneYear = expectedNumberOfBlocksPerDay() * 365; uint64_t twoPercentOfEmission = static_cast(static_cast(alreadyGeneratedCoins) / 100.0 * 2.0); baseReward = twoPercentOfEmission / blocksInOneYear; @@ -396,7 +397,7 @@ namespace CryptoNote { return Common::Format::parseAmount(str, amount); } - // Copyright (c) 2017-2018 Zawy + // The idea is based on Zawy's post // http://zawy1.blogspot.com/2017/12/using-difficulty-to-get-constant-value.html // Moore's law application by Sergey Kozlov uint64_t Currency::getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t avgCurrentReward, uint64_t avgHistoricDifficulty, uint64_t avgHistoricReward, uint32_t height) const { From 620327f3d14cc0d30cff9c5d89817c8e81fa35b8 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 2 Apr 2020 19:28:08 +0300 Subject: [PATCH 06/21] Align min fee calculation with whitepaper pt.1: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - replace avg daily reward with basic current reward (excluding penalty and fees) - clarify that our target fee is 0.25, although it's limited by max 0.1 finally, it must have been supposed to be 0.025?? ¯\_(ツ)_/¯ --- src/CryptoNoteCore/Blockchain.cpp | 18 +++++++++--------- src/CryptoNoteCore/Currency.cpp | 22 ++++++++-------------- src/CryptoNoteCore/Currency.h | 2 +- 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index bf24106b46..52862e8593 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -793,15 +793,15 @@ uint64_t Blockchain::getMinimalFee(uint32_t height) { } // calculate average difficulty for ~last month - uint64_t avgDifficultyCurrent = getAvgDifficulty(height, window * 7 * 4); - // historical reference trailing average difficulty - uint64_t avgDifficultyHistorical = m_blocks[height].cumulative_difficulty / height; - // calculate average reward for ~last day (base, excluding fees) - uint64_t avgRewardCurrent = (m_blocks[height].already_generated_coins - m_blocks[offset].already_generated_coins) / window; - // historical reference trailing average reward - uint64_t avgRewardHistorical = m_blocks[height].already_generated_coins / height; - - return m_currency.getMinimalFee(avgDifficultyCurrent, avgRewardCurrent, avgDifficultyHistorical, avgRewardHistorical, height); + uint64_t avgCurrentDifficulty = getAvgDifficulty(height, window * 7 * 4); + // reference trailing average difficulty + uint64_t avgReferenceDifficulty = m_blocks[height].cumulative_difficulty / height; + // calculate current base reward + uint64_t currentReward = m_currency.calculateReward(m_blocks[height].already_generated_coins); + // reference trailing average reward + uint64_t avgReferenceReward = m_blocks[height].already_generated_coins / height; + + return m_currency.getMinimalFee(avgCurrentDifficulty, currentReward, avgReferenceDifficulty, avgReferenceReward, height); } uint64_t Blockchain::getCoinsInCirculation() { diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 127ca8fdd0..6d8336916b 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -400,22 +400,16 @@ namespace CryptoNote { // The idea is based on Zawy's post // http://zawy1.blogspot.com/2017/12/using-difficulty-to-get-constant-value.html // Moore's law application by Sergey Kozlov - uint64_t Currency::getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t avgCurrentReward, uint64_t avgHistoricDifficulty, uint64_t avgHistoricReward, uint32_t height) const { + uint64_t Currency::getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t currentReward, uint64_t avgReferenceDifficulty, uint64_t avgReferenceReward, uint32_t height) const { uint64_t minimumFee(0); double minFee(0.0); - const double gauge = double(0.25); - const double baseFee = static_cast(CryptoNote::parameters::MAXIMUM_FEE); - - if (height <= CryptoNote::parameters::UPGRADE_HEIGHT_V5) { - const uint64_t blocksInTwoYears = expectedNumberOfBlocksPerDay() * 365 * 2; - double dailyDifficultyMoore = static_cast(avgCurrentDifficulty) / pow(2, static_cast(height) / static_cast(blocksInTwoYears)); - minFee = gauge * CryptoNote::parameters::COIN * static_cast(avgHistoricDifficulty) / - dailyDifficultyMoore * static_cast(avgCurrentReward) / static_cast(avgHistoricReward); - } - else { - minFee = baseFee * static_cast(avgHistoricDifficulty) / static_cast(avgCurrentDifficulty) * static_cast(avgCurrentReward) / static_cast(avgHistoricReward); - } - + const double baseFee = static_cast(250000000000); // why then the limit in the end is 100000000000, it must have been supposed to be 0.025?? + const uint64_t blocksInTwoYears = expectedNumberOfBlocksPerDay() * 365 * 2; + double currentDifficultyMoore = static_cast(avgCurrentDifficulty) / + pow(2, static_cast(height) / static_cast(blocksInTwoYears)); + minFee = baseFee * static_cast(avgReferenceDifficulty) / currentDifficultyMoore * + static_cast(currentReward) / static_cast(avgReferenceReward); + // zero test if (minFee == 0 || !std::isfinite(minFee)) return CryptoNote::parameters::MAXIMUM_FEE; diff --git a/src/CryptoNoteCore/Currency.h b/src/CryptoNoteCore/Currency.h index 94c74c4261..3aa03e58b4 100755 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -81,7 +81,7 @@ class Currency { uint64_t coin() const { return m_coin; } uint64_t minimumFee() const { return m_minimumFee; } - uint64_t getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t avgCurrentReward, uint64_t avgHistoricDifficulty, uint64_t avgHistoricReward, uint32_t height) const; + uint64_t getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t currentReward, uint64_t avgReferenceDifficulty, uint64_t avgReferenceReward, uint32_t height) const; uint64_t getFeePerByte(const uint64_t txExtraSize, const uint64_t minFee) const; uint64_t defaultDustThreshold() const { return m_defaultDustThreshold; } From f64d74a0dea7fabd7fa0888cadc68dd0639850c1 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 2 Apr 2020 19:48:03 +0300 Subject: [PATCH 07/21] Fix min fee supposed gauge along with per byte fee hardfork --- src/CryptoNoteCore/Currency.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 6d8336916b..286ecd54dc 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -403,7 +403,7 @@ namespace CryptoNote { uint64_t Currency::getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t currentReward, uint64_t avgReferenceDifficulty, uint64_t avgReferenceReward, uint32_t height) const { uint64_t minimumFee(0); double minFee(0.0); - const double baseFee = static_cast(250000000000); // why then the limit in the end is 100000000000, it must have been supposed to be 0.025?? + const double baseFee = height <= CryptoNote::parameters::FEE_PER_BYTE_HEIGHT ? static_cast(250000000000) : static_cast(25000000000); // it must have been supposed to be 0.025 const uint64_t blocksInTwoYears = expectedNumberOfBlocksPerDay() * 365 * 2; double currentDifficultyMoore = static_cast(avgCurrentDifficulty) / pow(2, static_cast(height) / static_cast(blocksInTwoYears)); From 1ec891eae0bf86298fc5b8fe6a3da42ebd5f7abb Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 2 Apr 2020 21:12:51 +0300 Subject: [PATCH 08/21] Add SMA difficulty function and use it in fee calc --- src/CryptoNoteCore/Blockchain.cpp | 30 ++++++++++++++++++++++++++++-- src/CryptoNoteCore/Blockchain.h | 1 + 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index 52862e8593..0b197f8ea4 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -767,6 +767,31 @@ difficulty_type Blockchain::getAvgDifficulty(uint32_t height) { return m_blocks[std::min(height, m_blocks.size())].cumulative_difficulty / std::min(height, m_blocks.size()); } +difficulty_type Blockchain::getSMADifficulty(uint32_t height, size_t window) { + std::lock_guard lk(m_blockchain_lock); + height = std::min(height, (uint32_t)m_blocks.size() - 1); + if (height <= 1) + return 1; + + size_t offset; + offset = height - std::min(height, std::min(static_cast(m_blocks.size() - 1), static_cast(window))); + if (offset == 0) { + ++offset; + } + + uint64_t cumulDiff = m_blocks[height].cumulative_difficulty - m_blocks[offset].cumulative_difficulty; + uint64_t solveTime = m_blocks[height].bl.timestamp - m_blocks[offset].bl.timestamp; + uint64_t adjWindow = std::min(static_cast(m_blocks.size() - 1), static_cast(window)); + uint64_t T = CryptoNote::parameters::DIFFICULTY_TARGET; + uint64_t low, high; + low = mul128(cumulDiff, T, &high); + if (high != 0) { + return 0; + } + + return low / (T * adjWindow / 2 + solveTime / 2); +} + uint64_t Blockchain::getBlockTimestamp(uint32_t height) { assert(height < m_blocks.size()); return m_blocks[height].bl.timestamp; @@ -793,7 +818,8 @@ uint64_t Blockchain::getMinimalFee(uint32_t height) { } // calculate average difficulty for ~last month - uint64_t avgCurrentDifficulty = getAvgDifficulty(height, window * 7 * 4); + // In whitepaper here stands SMA + uint64_t avgCurrentSMADifficulty = getSMADifficulty(height, window * 7 * 4); // reference trailing average difficulty uint64_t avgReferenceDifficulty = m_blocks[height].cumulative_difficulty / height; // calculate current base reward @@ -801,7 +827,7 @@ uint64_t Blockchain::getMinimalFee(uint32_t height) { // reference trailing average reward uint64_t avgReferenceReward = m_blocks[height].already_generated_coins / height; - return m_currency.getMinimalFee(avgCurrentDifficulty, currentReward, avgReferenceDifficulty, avgReferenceReward, height); + return m_currency.getMinimalFee(avgCurrentSMADifficulty, currentReward, avgReferenceDifficulty, avgReferenceReward, height); } uint64_t Blockchain::getCoinsInCirculation() { diff --git a/src/CryptoNoteCore/Blockchain.h b/src/CryptoNoteCore/Blockchain.h index a2c25920c5..ba2ea4c38f 100755 --- a/src/CryptoNoteCore/Blockchain.h +++ b/src/CryptoNoteCore/Blockchain.h @@ -94,6 +94,7 @@ namespace CryptoNote { difficulty_type getDifficultyForNextBlock(); difficulty_type getAvgDifficulty(uint32_t height); difficulty_type getAvgDifficulty(uint32_t height, size_t window); + difficulty_type getSMADifficulty(uint32_t height, size_t window); uint64_t getBlockTimestamp(uint32_t height); uint64_t getMinimalFee(uint32_t height); uint64_t getCoinsInCirculation(); From 0251ac452afb29e28868edbda1cc03a54fdbfe24 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 2 Apr 2020 21:14:57 +0300 Subject: [PATCH 09/21] The difference is not so significant, reverse SMA --- src/CryptoNoteCore/Blockchain.cpp | 30 ++---------------------------- src/CryptoNoteCore/Blockchain.h | 1 - 2 files changed, 2 insertions(+), 29 deletions(-) diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index 0b197f8ea4..52862e8593 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -767,31 +767,6 @@ difficulty_type Blockchain::getAvgDifficulty(uint32_t height) { return m_blocks[std::min(height, m_blocks.size())].cumulative_difficulty / std::min(height, m_blocks.size()); } -difficulty_type Blockchain::getSMADifficulty(uint32_t height, size_t window) { - std::lock_guard lk(m_blockchain_lock); - height = std::min(height, (uint32_t)m_blocks.size() - 1); - if (height <= 1) - return 1; - - size_t offset; - offset = height - std::min(height, std::min(static_cast(m_blocks.size() - 1), static_cast(window))); - if (offset == 0) { - ++offset; - } - - uint64_t cumulDiff = m_blocks[height].cumulative_difficulty - m_blocks[offset].cumulative_difficulty; - uint64_t solveTime = m_blocks[height].bl.timestamp - m_blocks[offset].bl.timestamp; - uint64_t adjWindow = std::min(static_cast(m_blocks.size() - 1), static_cast(window)); - uint64_t T = CryptoNote::parameters::DIFFICULTY_TARGET; - uint64_t low, high; - low = mul128(cumulDiff, T, &high); - if (high != 0) { - return 0; - } - - return low / (T * adjWindow / 2 + solveTime / 2); -} - uint64_t Blockchain::getBlockTimestamp(uint32_t height) { assert(height < m_blocks.size()); return m_blocks[height].bl.timestamp; @@ -818,8 +793,7 @@ uint64_t Blockchain::getMinimalFee(uint32_t height) { } // calculate average difficulty for ~last month - // In whitepaper here stands SMA - uint64_t avgCurrentSMADifficulty = getSMADifficulty(height, window * 7 * 4); + uint64_t avgCurrentDifficulty = getAvgDifficulty(height, window * 7 * 4); // reference trailing average difficulty uint64_t avgReferenceDifficulty = m_blocks[height].cumulative_difficulty / height; // calculate current base reward @@ -827,7 +801,7 @@ uint64_t Blockchain::getMinimalFee(uint32_t height) { // reference trailing average reward uint64_t avgReferenceReward = m_blocks[height].already_generated_coins / height; - return m_currency.getMinimalFee(avgCurrentSMADifficulty, currentReward, avgReferenceDifficulty, avgReferenceReward, height); + return m_currency.getMinimalFee(avgCurrentDifficulty, currentReward, avgReferenceDifficulty, avgReferenceReward, height); } uint64_t Blockchain::getCoinsInCirculation() { diff --git a/src/CryptoNoteCore/Blockchain.h b/src/CryptoNoteCore/Blockchain.h index ba2ea4c38f..a2c25920c5 100755 --- a/src/CryptoNoteCore/Blockchain.h +++ b/src/CryptoNoteCore/Blockchain.h @@ -94,7 +94,6 @@ namespace CryptoNote { difficulty_type getDifficultyForNextBlock(); difficulty_type getAvgDifficulty(uint32_t height); difficulty_type getAvgDifficulty(uint32_t height, size_t window); - difficulty_type getSMADifficulty(uint32_t height, size_t window); uint64_t getBlockTimestamp(uint32_t height); uint64_t getMinimalFee(uint32_t height); uint64_t getCoinsInCirculation(); From 6cd81bb9d92ebddb240d019c13ef611a3dda5d44 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 2 Apr 2020 21:16:07 +0300 Subject: [PATCH 10/21] Add note on possible difficulties reset in minimal fee calc. function --- src/CryptoNoteCore/Blockchain.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index 52862e8593..0a117821c4 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -792,6 +792,10 @@ uint64_t Blockchain::getMinimalFee(uint32_t height) { ++offset; } + /* Perhaps, in case of POW change, difficulties for calculations here + * should be reset and used starting from the fork height. + */ + // calculate average difficulty for ~last month uint64_t avgCurrentDifficulty = getAvgDifficulty(height, window * 7 * 4); // reference trailing average difficulty From d35f9c33087b6ebfa7e327d5d8919e2c41b1b7e1 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 2 Apr 2020 21:48:32 +0300 Subject: [PATCH 11/21] Delete empty spaces in getMinimalFee --- src/CryptoNoteCore/Currency.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 286ecd54dc..8c8e9cfa87 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -409,13 +409,13 @@ namespace CryptoNote { pow(2, static_cast(height) / static_cast(blocksInTwoYears)); minFee = baseFee * static_cast(avgReferenceDifficulty) / currentDifficultyMoore * static_cast(currentReward) / static_cast(avgReferenceReward); - + // zero test if (minFee == 0 || !std::isfinite(minFee)) return CryptoNote::parameters::MAXIMUM_FEE; minimumFee = static_cast(minFee); - + if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V5) { // Make all insignificant digits zero uint64_t i = 1000000000; From 35e5980ebeebc10c7922c5128265fa89e32ae962 Mon Sep 17 00:00:00 2001 From: aiwe Date: Fri, 3 Apr 2020 12:08:12 +0300 Subject: [PATCH 12/21] Fix upgrade height of min fee digits zeroing --- src/CryptoNoteCore/Currency.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 8c8e9cfa87..9d80640ece 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -416,7 +416,7 @@ namespace CryptoNote { minimumFee = static_cast(minFee); - if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V5) { + if (height > CryptoNote::parameters::FEE_PER_BYTE_HEIGHT) { // Make all insignificant digits zero uint64_t i = 1000000000; while (i > 1) { From 717d8662a59127569888ad2bf87eb8a5a66d6ea5 Mon Sep 17 00:00:00 2001 From: aiwe Date: Mon, 6 Apr 2020 11:58:05 +0300 Subject: [PATCH 13/21] Don't lower min tx fee too much --- src/CryptoNoteCore/Currency.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index 9d80640ece..443edacefe 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -403,7 +403,7 @@ namespace CryptoNote { uint64_t Currency::getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t currentReward, uint64_t avgReferenceDifficulty, uint64_t avgReferenceReward, uint32_t height) const { uint64_t minimumFee(0); double minFee(0.0); - const double baseFee = height <= CryptoNote::parameters::FEE_PER_BYTE_HEIGHT ? static_cast(250000000000) : static_cast(25000000000); // it must have been supposed to be 0.025 + const double baseFee = height <= CryptoNote::parameters::FEE_PER_BYTE_HEIGHT ? static_cast(250000000000) : static_cast(50000000000); const uint64_t blocksInTwoYears = expectedNumberOfBlocksPerDay() * 365 * 2; double currentDifficultyMoore = static_cast(avgCurrentDifficulty) / pow(2, static_cast(height) / static_cast(blocksInTwoYears)); From 64ce83b5ad40b67fb50aafff2c2f79f85191f00f Mon Sep 17 00:00:00 2001 From: aiwe Date: Mon, 6 Apr 2020 12:10:07 +0300 Subject: [PATCH 14/21] Cap the size of tx_extra in coinbase tx --- src/CryptoNoteConfig.h | 1 + src/CryptoNoteCore/Blockchain.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 9bad10cb41..b467102886 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -74,6 +74,7 @@ const uint64_t MAX_TX_MIXIN_SIZE = MAX_TX_MIXIN_SIZE const uint32_t MIN_TX_MIXIN_V1_HEIGHT = 216245; const uint32_t MIN_TX_MIXIN_V2_HEIGHT = 216394; const uint32_t FEE_PER_BYTE_HEIGHT = 490000; +const uint64_t MAX_EXTRA_SIZE = 1024; const uint64_t MAX_TRANSACTION_SIZE_LIMIT = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_CURRENT / 4 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index 0a117821c4..d5d94877ac 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -1124,6 +1124,16 @@ bool Blockchain::prevalidate_miner_transaction(const Block& b, uint32_t height) return false; } + uint64_t extraSize = (uint64_t)b.baseTransaction.extra.size(); + if (height > CryptoNote::parameters::FEE_PER_BYTE_HEIGHT && extraSize > CryptoNote::parameters::MAX_EXTRA_SIZE) { + logger(ERROR, BRIGHT_RED) + << "The miner transaction extra is too large in block " + << get_block_hash(b) << ". Allowed: " + << CryptoNote::parameters::MAX_EXTRA_SIZE + << ", actual: " << extraSize << "."; + return false; + } + return true; } From 4c7549e386ad32c068f78cf0d7c2b66f41e8cec8 Mon Sep 17 00:00:00 2001 From: aiwe Date: Mon, 6 Apr 2020 12:10:56 +0300 Subject: [PATCH 15/21] Correct few grammar errors in error messages in prevalidate_miner_transaction function --- src/CryptoNoteCore/Blockchain.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index d5d94877ac..530ebefca4 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -1089,19 +1089,19 @@ bool Blockchain::prevalidate_miner_transaction(const Block& b, uint32_t height) if (!(b.baseTransaction.inputs.size() == 1)) { logger(ERROR, BRIGHT_RED) - << "coinbase transaction in the block has no inputs"; + << "Coinbase transaction in the block has no inputs"; return false; } if (!(b.baseTransaction.signatures.empty())) { logger(ERROR, BRIGHT_RED) - << "coinbase transaction in the block shouldn't have signatures"; + << "Coinbase transaction in the block shouldn't have signatures"; return false; } if (!(b.baseTransaction.inputs[0].type() == typeid(BaseInput))) { logger(ERROR, BRIGHT_RED) - << "coinbase transaction in the block has the wrong type"; + << "Coinbase transaction in the block has the wrong type"; return false; } @@ -1113,14 +1113,14 @@ bool Blockchain::prevalidate_miner_transaction(const Block& b, uint32_t height) if (!(b.baseTransaction.unlockTime == height + (b.majorVersion < BLOCK_MAJOR_VERSION_5 ? m_currency.minedMoneyUnlockWindow() : m_currency.minedMoneyUnlockWindow_v1()))) { logger(ERROR, BRIGHT_RED) - << "coinbase transaction transaction have wrong unlock time=" + << "Coinbase transaction has wrong unlock time=" << b.baseTransaction.unlockTime << ", expected " << height + (b.majorVersion < BLOCK_MAJOR_VERSION_5 ? m_currency.minedMoneyUnlockWindow() : m_currency.minedMoneyUnlockWindow_v1()); return false; } if (!check_outs_overflow(b.baseTransaction)) { - logger(INFO, BRIGHT_RED) << "miner transaction have money overflow in block " << get_block_hash(b); + logger(ERROR, BRIGHT_RED) << "The miner transaction has money overflow in block " << get_block_hash(b); return false; } From 53df69564e4fa7aab802491f2b8b483e580f2bf1 Mon Sep 17 00:00:00 2001 From: aiwe Date: Wed, 15 Apr 2020 01:22:49 +0300 Subject: [PATCH 16/21] Schedule fork for unmixables together with fee per byte for tx extra on height 500000, also remove no longer needed conditions for old mixin forks --- src/CryptoNoteConfig.h | 9 +++------ src/CryptoNoteCore/Core.cpp | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index b467102886..18bc030f33 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -68,12 +68,9 @@ const uint64_t MAXIMUM_FEE = UINT64_C(10000000 const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(100000000); const uint64_t MIN_TX_MIXIN_SIZE = 2; -const uint64_t MAX_TX_MIXIN_SIZE_V1 = 50; -const uint64_t MAX_TX_MIXIN_SIZE_V2 = 20; -const uint64_t MAX_TX_MIXIN_SIZE = MAX_TX_MIXIN_SIZE_V2; -const uint32_t MIN_TX_MIXIN_V1_HEIGHT = 216245; -const uint32_t MIN_TX_MIXIN_V2_HEIGHT = 216394; -const uint32_t FEE_PER_BYTE_HEIGHT = 490000; +const uint64_t MAX_TX_MIXIN_SIZE = 20; +const uint32_t MIN_TX_MIXIN_HEIGHT = 216394; +const uint32_t FEE_PER_BYTE_HEIGHT = 500000; const uint64_t MAX_EXTRA_SIZE = 1024; const uint64_t MAX_TRANSACTION_SIZE_LIMIT = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_CURRENT / 4 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index 2a81450c8f..e957a88c5c 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -284,11 +284,8 @@ bool Core::check_tx_mixin(const Transaction& tx, uint32_t height) { assert(inputIndex < tx.signatures.size()); if (txin.type() == typeid(KeyInput)) { uint64_t txMixin = boost::get(txin).outputIndexes.size(); - if ((height > CryptoNote::parameters::MIN_TX_MIXIN_V1_HEIGHT && - height < CryptoNote::parameters::MIN_TX_MIXIN_V2_HEIGHT && - txMixin > CryptoNote::parameters::MAX_TX_MIXIN_SIZE_V1) || - (height > CryptoNote::parameters::MIN_TX_MIXIN_V2_HEIGHT && - txMixin > CryptoNote::parameters::MAX_TX_MIXIN_SIZE_V2)) { + if ((height > CryptoNote::parameters::MIN_TX_MIXIN_HEIGHT && + txMixin > CryptoNote::parameters::MAX_TX_MIXIN_SIZE)) { logger(ERROR) << "Transaction " << getObjectHash(tx) << " has too large mixIn count, rejected"; return false; } @@ -362,7 +359,7 @@ bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_ bool Core::check_tx_unmixable(const Transaction& tx, uint32_t height) { for (const auto& out : tx.outputs) { - if (!is_valid_decomposed_amount(out.amount) && height >= CryptoNote::parameters::UPGRADE_HEIGHT_V5) { + if (height >= CryptoNote::parameters::FEE_PER_BYTE_HEIGHT && !is_valid_decomposed_amount(out.amount)) { logger(ERROR) << "Invalid decomposed output amount " << out.amount << " for tx id= " << getObjectHash(tx); return false; } From db18fbb9e5acdc51019077bbf25c68563864d5f7 Mon Sep 17 00:00:00 2001 From: aiwe Date: Wed, 15 Apr 2020 13:00:01 +0300 Subject: [PATCH 17/21] It was the same (simultaneous) hardfork (fee v2 and min tx mixin) --- src/CryptoNoteConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 18bc030f33..f862ef269c 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -69,7 +69,7 @@ const uint64_t MAXIMUM_FEE = UINT64_C(10000000 const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(100000000); const uint64_t MIN_TX_MIXIN_SIZE = 2; const uint64_t MAX_TX_MIXIN_SIZE = 20; -const uint32_t MIN_TX_MIXIN_HEIGHT = 216394; +const uint32_t MIN_TX_MIXIN_HEIGHT = MINIMUM_FEE_V2_HEIGHT; const uint32_t FEE_PER_BYTE_HEIGHT = 500000; const uint64_t MAX_EXTRA_SIZE = 1024; From 10e3ee36cf95d9fa188eae8162f29263bd8f76dc Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 23 Apr 2020 20:30:27 +0300 Subject: [PATCH 18/21] Leave base for dynamic minimal fee intact --- src/CryptoNoteCore/Currency.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index de42159d37..bb9dfd6712 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -403,7 +403,7 @@ namespace CryptoNote { uint64_t Currency::getMinimalFee(uint64_t avgCurrentDifficulty, uint64_t currentReward, uint64_t avgReferenceDifficulty, uint64_t avgReferenceReward, uint32_t height) const { uint64_t minimumFee(0); double minFee(0.0); - const double baseFee = height <= CryptoNote::parameters::FEE_PER_BYTE_HEIGHT ? static_cast(250000000000) : static_cast(50000000000); + const double baseFee = static_cast(250000000000); const uint64_t blocksInTwoYears = expectedNumberOfBlocksPerDay() * 365 * 2; double currentDifficultyMoore = static_cast(avgCurrentDifficulty) / pow(2, static_cast(height) / static_cast(blocksInTwoYears)); From 6ac269ddb145c3180fb75f95eaf7704b1c998858 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 23 Apr 2020 20:37:34 +0300 Subject: [PATCH 19/21] Put all update heighs together, unify names, also hopefuly improve min fee and other tx validation components --- src/CryptoNoteConfig.h | 16 ++--- src/CryptoNoteCore/Blockchain.cpp | 2 +- src/CryptoNoteCore/Core.cpp | 91 +++++++++++++------------- src/CryptoNoteCore/Core.h | 10 +-- src/CryptoNoteCore/Currency.cpp | 4 +- src/CryptoNoteCore/ICore.h | 2 +- src/CryptoNoteCore/TransactionPool.cpp | 4 +- 7 files changed, 64 insertions(+), 65 deletions(-) diff --git a/src/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index f8cd7166f0..4ad70a79dc 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -61,15 +61,12 @@ const size_t CRYPTONOTE_DISPLAY_DECIMAL_POINT = 12; const uint64_t MINIMUM_FEE_V1 = UINT64_C(100000000); const uint64_t MINIMUM_FEE_V2 = UINT64_C(100000000000); -const uint32_t MINIMUM_FEE_V2_HEIGHT = 216394; const uint64_t MINIMUM_FEE = MINIMUM_FEE_V2; const uint64_t MAXIMUM_FEE = UINT64_C(100000000000); const uint64_t DEFAULT_DUST_THRESHOLD = UINT64_C(100000000); const uint64_t MIN_TX_MIXIN_SIZE = 2; const uint64_t MAX_TX_MIXIN_SIZE = 20; -const uint32_t MIN_TX_MIXIN_HEIGHT = MINIMUM_FEE_V2_HEIGHT; -const uint32_t FEE_PER_BYTE_HEIGHT = 500000; const uint64_t MAX_EXTRA_SIZE = 1024; const uint64_t MAX_TRANSACTION_SIZE_LIMIT = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_CURRENT / 4 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE; @@ -106,11 +103,14 @@ const size_t FUSION_TX_MAX_SIZE = CRYPTONOTE_BLOCK_ const size_t FUSION_TX_MIN_INPUT_COUNT = 12; const size_t FUSION_TX_MIN_IN_OUT_COUNT_RATIO = 4; -const uint32_t UPGRADE_HEIGHT_V2 = 60000; -const uint32_t UPGRADE_HEIGHT_V3 = 216000; -const uint32_t UPGRADE_HEIGHT_V4 = 266000; -const uint32_t UPGRADE_HEIGHT_LWMA3 = 300000; -const uint32_t UPGRADE_HEIGHT_V5 = 4294967294; +const uint32_t UPGRADE_HEIGHT_V2 = 60000; // Block v2, pre-LWMA +const uint32_t UPGRADE_HEIGHT_V3 = 216000; // Block v3, LWMA1 +const uint32_t UPGRADE_HEIGHT_V3_1 = 216394; // Min fee v2, cap max mixin +const uint32_t UPGRADE_HEIGHT_V4 = 266000; // Block v4, LWMA2, adaptive min fee, min mixin, disable slave merge mining +const uint32_t UPGRADE_HEIGHT_V4_1 = 300000; // LWMA3 +const uint32_t UPGRADE_HEIGHT_V4_2 = 500000; // Fee per-byte for extra, ban unmixable denominations +const uint32_t UPGRADE_HEIGHT_V5 = 4294967294; // Block v5, back to LWMA1+ + const unsigned UPGRADE_VOTING_THRESHOLD = 90; // percent const uint32_t UPGRADE_VOTING_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks const uint32_t UPGRADE_WINDOW = EXPECTED_NUMBER_OF_BLOCKS_PER_DAY; // blocks diff --git a/src/CryptoNoteCore/Blockchain.cpp b/src/CryptoNoteCore/Blockchain.cpp index 87843d4af9..c19eb9d82f 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -1125,7 +1125,7 @@ bool Blockchain::prevalidate_miner_transaction(const Block& b, uint32_t height) } uint64_t extraSize = (uint64_t)b.baseTransaction.extra.size(); - if (height > CryptoNote::parameters::FEE_PER_BYTE_HEIGHT && extraSize > CryptoNote::parameters::MAX_EXTRA_SIZE) { + if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V4_2 && extraSize > CryptoNote::parameters::MAX_EXTRA_SIZE) { logger(ERROR, BRIGHT_RED) << "The miner transaction extra is too large in block " << get_block_hash(b) << ". Allowed: " diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index e957a88c5c..1cdb181f8d 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -278,19 +278,19 @@ bool Core::get_stat_info(core_stat_info& st_inf) { return true; } -bool Core::check_tx_mixin(const Transaction& tx, uint32_t height) { +bool Core::check_tx_mixin(const Transaction& tx, const Crypto::Hash& txHash, uint32_t height) { size_t inputIndex = 0; for (const auto& txin : tx.inputs) { assert(inputIndex < tx.signatures.size()); if (txin.type() == typeid(KeyInput)) { uint64_t txMixin = boost::get(txin).outputIndexes.size(); - if ((height > CryptoNote::parameters::MIN_TX_MIXIN_HEIGHT && + if ((height > CryptoNote::parameters::UPGRADE_HEIGHT_V3_1 && txMixin > CryptoNote::parameters::MAX_TX_MIXIN_SIZE)) { - logger(ERROR) << "Transaction " << getObjectHash(tx) << " has too large mixIn count, rejected"; + logger(ERROR) << "Transaction " << Common::podToHex(txHash) << " has too large mixIn count, rejected"; return false; } if (getCurrentBlockMajorVersion() >= BLOCK_MAJOR_VERSION_4 && txMixin < m_currency.minMixin() && txMixin != 1) { - logger(ERROR) << "Transaction " << getObjectHash(tx) << " has mixIn count below the required minimum, rejected"; + logger(ERROR) << "Transaction " << Common::podToHex(txHash) << " has mixIn count below the required minimum, rejected"; return false; } ++inputIndex; @@ -299,7 +299,7 @@ bool Core::check_tx_mixin(const Transaction& tx, uint32_t height) { return true; } -bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_context& tvc, uint32_t height) { +bool Core::check_tx_fee(const Transaction& tx, const Crypto::Hash& txHash, size_t blobSize, tx_verification_context& tvc, uint32_t height) { uint64_t inputs_amount = 0; if (!get_inputs_money_amount(tx, inputs_amount)) { tvc.m_verification_failed = true; @@ -315,41 +315,40 @@ bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_ return false; } - // tx extra size in bytes, uint8_t is a one byte - uint64_t extraSize = (uint64_t)tx.extra.size(); - - // To prevent blockchain bloat it's possible to just limit max tx extra size - // or charge fee per byte for the size exceeding free limit, 100 bytes is - // enough to contain data of the ordinary tx (public key, payment id, etc.) - - Crypto::Hash h = NULL_HASH; - getObjectHash(tx, h, blobSize); const uint64_t fee = inputs_amount - outputs_amount; bool isFusionTransaction = fee == 0 && m_currency.isFusionTransaction(tx, blobSize, height); - bool enough = true; - if (!isFusionTransaction && !m_checkpoints.is_in_checkpoint_zone(getCurrentBlockchainHeight())) { - if (getBlockMajorVersionForHeight(height) < BLOCK_MAJOR_VERSION_4) { - if (fee < CryptoNote::parameters::MINIMUM_FEE_V1) { - logger(INFO) << "[Core] Transaction fee is not enough: " << m_currency.formatAmount(fee) << ", minimum fee: " << m_currency.formatAmount(CryptoNote::parameters::MINIMUM_FEE_V1); + if (!isFusionTransaction && !m_checkpoints.is_in_checkpoint_zone(height)) { + bool enough = true; + + if (height < CryptoNote::parameters::UPGRADE_HEIGHT_V3_1 && fee < CryptoNote::parameters::MINIMUM_FEE_V1 || + height > CryptoNote::parameters::UPGRADE_HEIGHT_V3_1 && height <= CryptoNote::parameters::UPGRADE_HEIGHT_V4 && fee < CryptoNote::parameters::MINIMUM_FEE_V2) + { + enough = false; + } + else if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V4) { + uint64_t min = getMinimalFeeForHeight(height); + + if (fee < (min - (min * 20 / 100))) { enough = false; } - } else { - uint64_t min = getMinimalFeeForHeight(height); - if (height > CryptoNote::parameters::FEE_PER_BYTE_HEIGHT) { + if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V4_2) { + uint64_t extraSize = (uint64_t)tx.extra.size(); uint64_t feePerByte = m_currency.getFeePerByte(extraSize, min); min += feePerByte; - } - - if (fee < (min - min * 20 / 100)) { - logger(INFO) << "[Core] Transaction fee is not enough: " << m_currency.formatAmount(fee) << ", minimum fee: " << m_currency.formatAmount(min); - enough = false; + if (fee < (min - min * 20 / 100)) { + logger(DEBUGGING) << "Transaction fee is insufficient due to additional data in extra"; + enough = false; + } } } - if (!enough) { + if (!enough) { tvc.m_verification_failed = true; tvc.m_tx_fee_too_small = true; + logger(DEBUGGING) << "The fee for transaction " + << Common::podToHex(txHash) + << " is insufficient and it is not a fusion transaction"; return false; } } @@ -357,24 +356,24 @@ bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_ return true; } -bool Core::check_tx_unmixable(const Transaction& tx, uint32_t height) { +bool Core::check_tx_unmixable(const Transaction& tx, const Crypto::Hash& txHash, uint32_t height) { for (const auto& out : tx.outputs) { - if (height >= CryptoNote::parameters::FEE_PER_BYTE_HEIGHT && !is_valid_decomposed_amount(out.amount)) { - logger(ERROR) << "Invalid decomposed output amount " << out.amount << " for tx id= " << getObjectHash(tx); + if (height >= CryptoNote::parameters::UPGRADE_HEIGHT_V4_2 && !is_valid_decomposed_amount(out.amount)) { + logger(ERROR) << "Invalid decomposed output amount " << out.amount << " for tx id= " << Common::podToHex(txHash); return false; } } return true; } -bool Core::check_tx_semantic(const Transaction& tx, bool keeped_by_block) { +bool Core::check_tx_semantic(const Transaction& tx, const Crypto::Hash& txHash, bool keeped_by_block) { if (!tx.inputs.size()) { - logger(ERROR) << "tx with empty inputs, rejected for tx id= " << getObjectHash(tx); + logger(ERROR) << "tx with empty inputs, rejected for tx id= " << Common::podToHex(txHash); return false; } if (tx.inputs.size() != tx.signatures.size()) { - logger(ERROR) << "tx signatures size doesn't match inputs size, rejected for tx id= " << getObjectHash(tx); + logger(ERROR) << "tx signatures size doesn't match inputs size, rejected for tx id= " << Common::podToHex(txHash); return false; } @@ -382,25 +381,25 @@ bool Core::check_tx_semantic(const Transaction& tx, bool keeped_by_block) { if (tx.inputs[i].type() == typeid(KeyInput)) { if (boost::get(tx.inputs[i]).outputIndexes.size() != tx.signatures[i].size()) { logger(ERROR) << "tx signatures count doesn't match outputIndexes count for input " - << i << ", rejected for tx id= " << getObjectHash(tx); + << i << ", rejected for tx id= " << Common::podToHex(txHash); return false; } } } if (!check_inputs_types_supported(tx)) { - logger(ERROR) << "unsupported input types for tx id= " << getObjectHash(tx); + logger(ERROR) << "unsupported input types for tx id= " << Common::podToHex(txHash); return false; } std::string errmsg; if (!check_outs_valid(tx, &errmsg)) { - logger(ERROR) << "tx with invalid outputs, rejected for tx id= " << getObjectHash(tx) << ": " << errmsg; + logger(ERROR) << "tx with invalid outputs, rejected for tx id= " << Common::podToHex(txHash) << ": " << errmsg; return false; } if (!check_money_overflow(tx)) { - logger(ERROR) << "tx have money overflow, rejected for tx id= " << getObjectHash(tx); + logger(ERROR) << "tx have money overflow, rejected for tx id= " << Common::podToHex(txHash); return false; } @@ -409,7 +408,7 @@ bool Core::check_tx_semantic(const Transaction& tx, bool keeped_by_block) { uint64_t amount_out = get_outs_money_amount(tx); if (amount_in < amount_out) { - logger(ERROR) << "tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << getObjectHash(tx); + logger(ERROR) << "tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << Common::podToHex(txHash); return false; } @@ -780,7 +779,7 @@ bool Core::parse_tx_from_blob(Transaction& tx, Crypto::Hash& tx_hash, Crypto::Ha return parseAndValidateTransactionFromBinaryArray(blob, tx, tx_hash, tx_prefix_hash); } -bool Core::check_tx_syntax(const Transaction& tx) { +bool Core::check_tx_syntax(const Transaction& tx, const Crypto::Hash& tx_hash) { return true; } @@ -1238,7 +1237,7 @@ bool Core::getPaymentId(const Transaction& transaction, Crypto::Hash& paymentId) } bool Core::handleIncomingTransaction(const Transaction& tx, const Crypto::Hash& txHash, size_t blobSize, tx_verification_context& tvc, bool keptByBlock, uint32_t height) { - if (!check_tx_syntax(tx)) { + if (!check_tx_syntax(tx, txHash)) { logger(INFO) << "WRONG TRANSACTION BLOB, Failed to check tx " << txHash << " syntax, rejected"; tvc.m_verification_failed = true; return false; @@ -1252,26 +1251,26 @@ bool Core::handleIncomingTransaction(const Transaction& tx, const Crypto::Hash& return false; } - if (!check_tx_fee(tx, blobSize, tvc, height)) { + if (!check_tx_fee(tx, txHash, blobSize, tvc, height)) { tvc.m_verification_failed = true; return false; } - if (!check_tx_mixin(tx, height)) { + if (!check_tx_mixin(tx, txHash, height)) { logger(INFO) << "Transaction verification failed: mixin count for transaction " << txHash << " is too large, rejected"; tvc.m_verification_failed = true; return false; } - if (!check_tx_unmixable(tx, height)) { + if (!check_tx_unmixable(tx, txHash, height)) { logger(ERROR) << "Transaction verification failed: unmixable output for transaction " << txHash << ", rejected"; tvc.m_verification_failed = true; return false; - } + } } - if (!check_tx_semantic(tx, keptByBlock)) { + if (!check_tx_semantic(tx, txHash, keptByBlock)) { logger(INFO) << "WRONG TRANSACTION BLOB, Failed to check tx " << txHash << " semantic, rejected"; tvc.m_verification_failed = true; return false; diff --git a/src/CryptoNoteCore/Core.h b/src/CryptoNoteCore/Core.h index 5e49f17996..0ebc568d1c 100755 --- a/src/CryptoNoteCore/Core.h +++ b/src/CryptoNoteCore/Core.h @@ -189,15 +189,15 @@ namespace CryptoNote { bool load_state_data(); bool parse_tx_from_blob(Transaction& tx, Crypto::Hash& tx_hash, Crypto::Hash& tx_prefix_hash, const BinaryArray& blob); - bool check_tx_syntax(const Transaction& tx); + bool check_tx_syntax(const Transaction& txc, const Crypto::Hash& txHash); //check correct values, amounts and all lightweight checks not related with database - bool check_tx_semantic(const Transaction& tx, bool keeped_by_block); + bool check_tx_semantic(const Transaction& tx, const Crypto::Hash& txHash, bool keeped_by_block); //check if tx already in memory pool or in main blockchain - bool check_tx_mixin(const Transaction& tx, uint32_t height); + bool check_tx_mixin(const Transaction& tx, const Crypto::Hash& txHash, uint32_t height); //check if the mixin is not too large - virtual bool check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_context& tvc, uint32_t height) override; + virtual bool check_tx_fee(const Transaction& tx, const Crypto::Hash& txHash, size_t blobSize, tx_verification_context& tvc, uint32_t height) override; //check if tx is not sending unmixable outputs - bool check_tx_unmixable(const Transaction& tx, uint32_t height); + bool check_tx_unmixable(const Transaction& tx, const Crypto::Hash& txHash, uint32_t height); bool update_miner_block_template(); bool handle_command_line(const boost::program_options::variables_map& vm); diff --git a/src/CryptoNoteCore/Currency.cpp b/src/CryptoNoteCore/Currency.cpp index bb9dfd6712..0f403aa9a5 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -416,7 +416,7 @@ namespace CryptoNote { minimumFee = static_cast(minFee); - if (height > CryptoNote::parameters::FEE_PER_BYTE_HEIGHT) { + if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V4_2) { // Make all insignificant digits zero uint64_t i = 1000000000; while (i > 1) { @@ -651,7 +651,7 @@ namespace CryptoNote { int64_t max_TS, prev_max_TS; prev_max_TS = timestamps[0]; - uint32_t lwma3_height = CryptoNote::parameters::UPGRADE_HEIGHT_LWMA3; + uint32_t lwma3_height = CryptoNote::parameters::UPGRADE_HEIGHT_V4_1; for (int64_t i = 1; i <= N; i++) { if (height < lwma3_height) { // LWMA-2 diff --git a/src/CryptoNoteCore/ICore.h b/src/CryptoNoteCore/ICore.h index 268efc0f7c..6835d2425d 100755 --- a/src/CryptoNoteCore/ICore.h +++ b/src/CryptoNoteCore/ICore.h @@ -123,7 +123,7 @@ class ICore { virtual uint64_t getMinimalFee() = 0; virtual uint64_t getNextBlockDifficulty() = 0; virtual uint64_t getTotalGeneratedAmount() = 0; - virtual bool check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_context& tvc, uint32_t height) = 0; + virtual bool check_tx_fee(const Transaction& tx, const Crypto::Hash& txHash, size_t blobSize, tx_verification_context& tvc, uint32_t height) = 0; virtual size_t getPoolTransactionsCount() = 0; virtual size_t getBlockchainTotalTransactions() = 0; virtual uint32_t getCurrentBlockchainHeight() = 0; diff --git a/src/CryptoNoteCore/TransactionPool.cpp b/src/CryptoNoteCore/TransactionPool.cpp index cd2fa4f046..9df547abe7 100644 --- a/src/CryptoNoteCore/TransactionPool.cpp +++ b/src/CryptoNoteCore/TransactionPool.cpp @@ -425,8 +425,8 @@ namespace CryptoNote { } tx_verification_context tvc = boost::value_initialized(); - if (!m_core.check_tx_fee(txd.tx, txd.blobSize, tvc, m_core.getCurrentBlockchainHeight())) { - logger(DEBUGGING) << "Transaction " << txd.id << " not included to block template because fee is too small"; + if (!m_core.check_tx_fee(txd.tx, getObjectHash(txd.tx), txd.blobSize, tvc, m_core.getCurrentBlockchainHeight())) { + logger(DEBUGGING) << "Transaction " << txd.id << " not included to block template because fee is insufficient"; continue; } From 81501ed9dce4cfcbbd0f3afd4de5abf3132106ac Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 23 Apr 2020 20:42:27 +0300 Subject: [PATCH 20/21] Add minor correction to condition in min fee check --- src/CryptoNoteCore/Core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index 1cdb181f8d..c657f3a78e 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -320,7 +320,7 @@ bool Core::check_tx_fee(const Transaction& tx, const Crypto::Hash& txHash, size_ if (!isFusionTransaction && !m_checkpoints.is_in_checkpoint_zone(height)) { bool enough = true; - if (height < CryptoNote::parameters::UPGRADE_HEIGHT_V3_1 && fee < CryptoNote::parameters::MINIMUM_FEE_V1 || + if (height <= CryptoNote::parameters::UPGRADE_HEIGHT_V3_1 && fee < CryptoNote::parameters::MINIMUM_FEE_V1 || height > CryptoNote::parameters::UPGRADE_HEIGHT_V3_1 && height <= CryptoNote::parameters::UPGRADE_HEIGHT_V4 && fee < CryptoNote::parameters::MINIMUM_FEE_V2) { enough = false; From 9740033b6bd73bf0dba1b0b8810877cd174ce764 Mon Sep 17 00:00:00 2001 From: aiwe Date: Thu, 30 Apr 2020 16:52:30 +0300 Subject: [PATCH 21/21] Clean stray spaces --- src/CryptoNoteCore/Core.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index c657f3a78e..24602dd950 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -343,7 +343,7 @@ bool Core::check_tx_fee(const Transaction& tx, const Crypto::Hash& txHash, size_ } } - if (!enough) { + if (!enough) { tvc.m_verification_failed = true; tvc.m_tx_fee_too_small = true; logger(DEBUGGING) << "The fee for transaction "