Skip to content

Commit

Permalink
cryptonote_core: misc v17 consensus rules
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffro256 committed Jan 29, 2025
1 parent c6f2ccd commit ebed0b7
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 7 deletions.
4 changes: 4 additions & 0 deletions src/cryptonote_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,10 @@
#define HF_VERSION_BULLETPROOF_PLUS 15
#define HF_VERSION_VIEW_TAGS 15
#define HF_VERSION_2021_SCALING 15
#define HF_VERSION_FCMP 17
#define HF_VERSION_REJECT_UNLOCK_TIME 17
#define HF_VERSION_REJECT_LARGE_EXTRA 17
#define HF_VERSION_REJECT_UNMIXABLE_V1 17

#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
#define CRYPTONOTE_SCALING_2021_FEE_ROUNDING_PLACES 2
Expand Down
4 changes: 2 additions & 2 deletions src/cryptonote_core/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3436,14 +3436,14 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}

// min/max tx version based on HF, and we accept v1 txes if having a non mixable
const size_t max_tx_version = (hf_version <= 3) ? 1 : 2;
const size_t max_tx_version = get_maximum_transaction_version(hf_version);
if (tx.version > max_tx_version)
{
MERROR_VER("transaction version " << (unsigned)tx.version << " is higher than max accepted version " << max_tx_version);
tvc.m_verifivation_failed = true;
return false;
}
const size_t min_tx_version = (n_unmixable > 0 ? 1 : (hf_version >= HF_VERSION_ENFORCE_RCT) ? 2 : 1);
const size_t min_tx_version = get_minimum_transaction_version(hf_version, n_unmixable > 0);
if (tx.version < min_tx_version)
{
MERROR_VER("transaction version " << (unsigned)tx.version << " is lower than min accepted version " << min_tx_version);
Expand Down
53 changes: 50 additions & 3 deletions src/cryptonote_core/tx_verification_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ static bool ver_non_input_consensus_templated(TxForwardIt tx_begin, TxForwardIt
std::vector<const rct::rctSig*> rvv;
rvv.reserve(static_cast<size_t>(std::distance(tx_begin, tx_end)));

const size_t max_tx_version = hf_version < HF_VERSION_DYNAMIC_FEE ? 1 : 2;
// We assume transactions have an unmixable ring since it's more permissive. The version is
// checked again in Blockchain::check_tx_inputs() with `has_unmixable_ring` actually resolved.
const size_t min_tx_version = get_minimum_transaction_version(hf_version, /*has_unmixable_ring=*/true);
const size_t max_tx_version = get_maximum_transaction_version(hf_version);

const size_t tx_weight_limit = get_transaction_weight_limit(hf_version);

Expand All @@ -153,13 +156,29 @@ static bool ver_non_input_consensus_templated(TxForwardIt tx_begin, TxForwardIt
return false;
}

// Rule 2 & 3
if (tx.version == 0 || tx.version > max_tx_version)
// Rule 2 and Rule 3
if (tx.version < min_tx_version || tx.version > max_tx_version)
{
tvc.m_verifivation_failed = true;
return false;
}

// Rule 8
if (hf_version >= HF_VERSION_REJECT_UNLOCK_TIME && tx.unlock_time != 0)
{
tvc.m_verifivation_failed = true;
tvc.m_nonzero_unlock_time = true;
return false;
}

// Rule 9
if (hf_version >= HF_VERSION_REJECT_LARGE_EXTRA && tx.extra.size() > MAX_TX_EXTRA_SIZE)
{
tvc.m_verifivation_failed = true;
tvc.m_tx_extra_too_big = true;
return false;
}

// Rule 4
const size_t tx_weight = get_transaction_weight(tx, blob_size);
if (hf_version >= HF_VERSION_PER_BYTE_FEE && tx_weight > tx_weight_limit)
Expand Down Expand Up @@ -207,6 +226,34 @@ uint64_t get_transaction_weight_limit(const uint8_t hf_version)
return get_min_block_weight(hf_version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
}

size_t get_minimum_transaction_version(uint8_t hf_version, bool has_unmixable_ring)
{
if (hf_version >= HF_VERSION_REJECT_UNMIXABLE_V1)
{
return 2;
}
else if (hf_version < HF_VERSION_ENFORCE_RCT)
{
return 1;
}
else // HF_VERSION_ENFORCE_RCT <= hf_version < HF_VERSION_REJECT_UNMIXABLE_V1
{
return has_unmixable_ring ? 1 : 2;
}
}

size_t get_maximum_transaction_version(uint8_t hf_version)
{
if (hf_version >= HF_VERSION_DYNAMIC_FEE)
{
return 2;
}
else // hf_version < HF_VERSION_DYNAMIC_FEE
{
return 1;
}
}

bool ver_rct_non_semantics_simple_cached
(
transaction& tx,
Expand Down
27 changes: 25 additions & 2 deletions src/cryptonote_core/tx_verification_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,27 @@ namespace cryptonote
*/
uint64_t get_transaction_weight_limit(uint8_t hf_version);

/**
* @brief Get the minimum allowed transaction version
*
* An "unmixable" ring is a ring appearing in block index BI spending a pre-RingCT enote
* (i.e. referencible amount != 0) where the minimum required ring size is greater than the total
* number of pre-RingCT enotes on-chain at block indices < BI with that same amount.
*
* @param hf_version hard fork version
* @param has_unmixable_ring true iff at least one of the rings in the transaction is "unmixable"
* @return the minimum allowed transaction version
*/
size_t get_minimum_transaction_version(uint8_t hf_version, bool has_unmixable_ring);

/**
* @brief Get the maximum allowed transaction version
*
* @param hf_version hard fork version
* @return the maximum allowed transaction version
*/
size_t get_maximum_transaction_version(uint8_t hf_version);

// Modifying this value should not affect consensus. You can adjust it for performance needs
static constexpr const size_t RCT_VER_CACHE_SIZE = 8192;

Expand Down Expand Up @@ -112,12 +133,14 @@ struct pool_supplement
*
* List of checks that we do for each transaction:
* 1. Check tx blob size < get_max_tx_size()
* 2. Check tx version != 0
* 3. Check tx version is less than maximum for given hard fork version
* 2. Check tx version >= get_minimum_transaction_version()
* 3. Check tx version <= get_maximum_transaction_version()
* 4. Check tx weight < get_transaction_weight_limit()
* 5. Passes core::check_tx_semantic()
* 6. Passes Blockchain::check_tx_outputs()
* 7. Passes ver_mixed_rct_semantics() [Uses batch RingCT verification when applicable]
* 8. Check unlock time is 0 from hardfork v17
* 9. Check extra size <= MAX_TX_EXTRA_SIZE from hardfork v17
*
* For pool_supplement input:
* We assume the structure of the pool supplement is already correct: for each value entry, the
Expand Down

0 comments on commit ebed0b7

Please sign in to comment.