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/CryptoNoteConfig.h b/src/CryptoNoteConfig.h index 894c2af3df..4ad70a79dc 100644 --- a/src/CryptoNoteConfig.h +++ b/src/CryptoNoteConfig.h @@ -61,17 +61,14 @@ 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_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 uint64_t MAX_TX_MIXIN_SIZE = 20; +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; const size_t DANDELION_EPOCH = 600; @@ -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 abea36f2a4..c19eb9d82f 100644 --- a/src/CryptoNoteCore/Blockchain.cpp +++ b/src/CryptoNoteCore/Blockchain.cpp @@ -792,16 +792,20 @@ 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 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; + 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(avgDifficultyCurrent, avgRewardCurrent, avgDifficultyHistorical, avgRewardHistorical, height); + return m_currency.getMinimalFee(avgCurrentDifficulty, currentReward, avgReferenceDifficulty, avgReferenceReward, height); } uint64_t Blockchain::getCoinsInCirculation() { @@ -1085,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; } @@ -1109,14 +1113,24 @@ bool Blockchain::prevalidate_miner_transaction(const Block& b, uint32_t height) if (!(b.baseTransaction.unlockTime == height + m_currency.minedMoneyUnlockWindow())) { logger(ERROR, BRIGHT_RED) - << "coinbase transaction transaction have wrong unlock time=" + << "Coinbase transaction has wrong unlock time=" << b.baseTransaction.unlockTime << ", expected " << (height + m_currency.minedMoneyUnlockWindow()); 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; + } + + uint64_t extraSize = (uint64_t)b.baseTransaction.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: " + << CryptoNote::parameters::MAX_EXTRA_SIZE + << ", actual: " << extraSize << "."; return false; } diff --git a/src/CryptoNoteCore/Core.cpp b/src/CryptoNoteCore/Core.cpp index c059e2e004..24602dd950 100755 --- a/src/CryptoNoteCore/Core.cpp +++ b/src/CryptoNoteCore/Core.cpp @@ -278,22 +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_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)) { - logger(ERROR) << "Transaction " << getObjectHash(tx) << " has too large mixIn count, rejected"; + if ((height > CryptoNote::parameters::UPGRADE_HEIGHT_V3_1 && + txMixin > CryptoNote::parameters::MAX_TX_MIXIN_SIZE)) { + 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; @@ -302,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; @@ -318,28 +315,40 @@ bool Core::check_tx_fee(const Transaction& tx, size_t blobSize, tx_verification_ return false; } - 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); - enough = false; - } - } else { + 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)) { - logger(INFO) << "[Core] Transaction fee is not enough: " << m_currency.formatAmount(fee) << ", minimum fee: " << m_currency.formatAmount(min); + + if (fee < (min - (min * 20 / 100))) { enough = false; } + + 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(DEBUGGING) << "Transaction fee is insufficient due to additional data in extra"; + enough = false; + } + } } 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; } } @@ -347,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 (!is_valid_decomposed_amount(out.amount) && height >= CryptoNote::parameters::UPGRADE_HEIGHT_V5) { - 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; } @@ -372,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; } @@ -399,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; } @@ -770,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; } @@ -1228,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; @@ -1242,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 22e5fe0f1a..0f403aa9a5 100755 --- a/src/CryptoNoteCore/Currency.cpp +++ b/src/CryptoNoteCore/Currency.cpp @@ -147,44 +147,53 @@ 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; + // 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; + } - // 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); @@ -388,32 +397,26 @@ 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 { + 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); + 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; minimumFee = static_cast(minFee); - - if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V5) { + + if (height > CryptoNote::parameters::UPGRADE_HEIGHT_V4_2) { // Make all insignificant digits zero uint64_t i = 1000000000; while (i > 1) { @@ -425,6 +428,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); @@ -642,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/Currency.h b/src/CryptoNoteCore/Currency.h index 38c507ee1f..b878d89abb 100755 --- a/src/CryptoNoteCore/Currency.h +++ b/src/CryptoNoteCore/Currency.h @@ -80,7 +80,9 @@ 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; } uint64_t difficultyTarget() const { return m_difficultyTarget; } @@ -140,6 +142,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; 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; } 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) {