Skip to content

Commit

Permalink
Transaction fees per byte for extra data (#122)
Browse files Browse the repository at this point in the history
* Show tx extra size in bytes in explorer (Tx extra is a vector or uint8_t which is already one byte so we can just use this vector's size)
* Introduce fee per byte for transaction extra (exceeding the free limit of 100 bytes which is enough for a 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.
* Calculate basic reward separately from the calculation of final block reward and possible penalty
* A little clarification on tail reward calc. with reference to the whitepaper
* Align min fee calculation with whitepaper pt.1:
 - 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?? ¯\_(ツ)_/¯
* Cap the size of tx_extra in coinbase tx
* Correct few grammar errors in error messages in prevalidate_miner_transaction function
* Schedule fork for unmixables together with a fee per byte for tx extra on height 500000, also remove no longer needed conditions for old mixin forks
* Put all update heights together, unify names, also hopefully improve min fee and other tx validation components
  • Loading branch information
aivve authored Apr 30, 2020
1 parent 42f632d commit cd176ae
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 134 deletions.
28 changes: 15 additions & 13 deletions include/BlockchainExplorerData.h
Original file line number Diff line number Diff line change
@@ -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.
//
Expand Down Expand Up @@ -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<TransactionOutputReferenceDetails> outputs;
KeyInput input;
uint64_t mixin;
std::vector<TransactionOutputReferenceDetails> outputs;
};

struct MultisignatureInputDetails {
MultisignatureInput input;
TransactionOutputReferenceDetails output;
MultisignatureInput input;
TransactionOutputReferenceDetails output;
};

typedef boost::variant<BaseInputDetails, KeyInputDetails, MultisignatureInputDetails> transactionInputDetails2;

struct TransactionExtraDetails2 {
std::vector<size_t> padding;
Crypto::PublicKey publicKey;
BinaryArray nonce;
BinaryArray raw;
std::vector<size_t> padding;
Crypto::PublicKey publicKey;
BinaryArray nonce;
BinaryArray raw;
size_t size = 0;
};

struct TransactionDetails {
Expand Down
2 changes: 2 additions & 0 deletions src/BlockchainExplorer/BlockchainExplorerDataBuilder.cpp
Original file line number Diff line number Diff line change
@@ -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.
//
Expand Down Expand Up @@ -70,6 +71,7 @@ bool BlockchainExplorerDataBuilder::fillTxExtra(const std::vector<uint8_t>& rawE
extraDetails.nonce = boost::get<TransactionExtraNonce>(field).nonce;
}
}
extraDetails.size = rawExtra.size();
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/BlockchainExplorer/BlockchainExplorerDataBuilder.h
Original file line number Diff line number Diff line change
@@ -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.
//
Expand Down
22 changes: 11 additions & 11 deletions src/CryptoNoteConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
40 changes: 27 additions & 13 deletions src/CryptoNoteCore/Blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
}

Expand Down
Loading

0 comments on commit cd176ae

Please sign in to comment.