diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 06af55c..4018a60 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1571,10 +1571,13 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons // Get the current tally value for the source currency type MDB_val_copy source_idx(asset.first); boost::multiprecision::int128_t source_tally = 0; + std::string asset_symbol = cryptonote::asset_type_from_id(asset.first); + const bool is_base_asset = + asset.first == 0x50455900 /*PEY*/ || + asset.first == 0x4255524E /*BURN*/; result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally); if (result == MDB_NOTFOUND){ - std::string asset_symbol = cryptonote::asset_type_from_id(asset.first); - if (asset.first == 0x53414C31 /*SAL1*/ || asset.first == 0x53414C00 /*SAL*/) { + if (is_base_asset) { throw0(DB_ERROR(("Asset " + asset_symbol + " not found when updating circulating supply for PROTOCOL_TX").c_str())); } else{ @@ -1583,6 +1586,9 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons } else if (result) throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str())); + else if (!is_base_asset && source_tally > 0) { + throw0(DB_ERROR(("Unexpected remint of existing custom asset in PROTOCOL_TX: " + asset_symbol).c_str())); + } if (source_tally > source_tally + asset.second) throw0(DB_ERROR("add_transaction_data() - mint overflow")); boost::multiprecision::int128_t final_source_tally = source_tally + asset.second; @@ -1600,9 +1606,10 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally); if (result && result != MDB_NOTFOUND) throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str())); - if (burn_tally < asset.second) + const uint64_t burn_amount = asset.second; + if (burn_tally < burn_amount) throw0(DB_ERROR("add_transaction_data() - burn underflow")); - boost::multiprecision::int128_t final_burn_tally = burn_tally - asset.second; + boost::multiprecision::int128_t final_burn_tally = burn_tally - burn_amount; write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally); } // LAND AHOY!!! diff --git a/src/carrot_impl/format_utils.cpp b/src/carrot_impl/format_utils.cpp index 5941858..c0add8e 100644 --- a/src/carrot_impl/format_utils.cpp +++ b/src/carrot_impl/format_utils.cpp @@ -437,7 +437,8 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( const std::vector &enotes, const cryptonote::blobdata &extra_nonce, const cryptonote::transaction_type &tx_type, - const std::uint64_t block_index) + const std::uint64_t block_index, + const std::uint8_t hf_version) { CARROT_CHECK_AND_THROW(tx_type == cryptonote::transaction_type::MINER || tx_type == cryptonote::transaction_type::PROTOCOL, invalid_tx_type, "invalid tx_type : is not MINER or PROTOCOL"); const size_t nouts = enotes.size(); @@ -445,8 +446,8 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( cryptonote::transaction tx; tx.type = tx_type; tx.pruned = false; - tx.version = TRANSACTION_VERSION_CARROT; - tx.unlock_time = CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + tx.version = (hf_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT; + tx.unlock_time = block_index + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; tx.vin.reserve(1); tx.vout.reserve(nouts); tx.extra.reserve(MAX_TX_EXTRA_SIZE); @@ -486,7 +487,8 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( cryptonote::transaction make_single_enote_carrot_coinbase_transaction_v1(const CarrotDestinationV1 &destination, const rct::xmr_amount block_reward, const std::uint64_t block_index, - const cryptonote::blobdata &extra_nonce) + const cryptonote::blobdata &extra_nonce, + const std::uint8_t hf_version) { CHECK_AND_ASSERT_THROW_MES(!destination.is_subaddress, "make_single_enote_carrot_coinbase_transaction_v1: subaddress are not allowed in miner transactions"); @@ -503,7 +505,7 @@ cryptonote::transaction make_single_enote_carrot_coinbase_transaction_v1(const C std::vector enotes(1); get_coinbase_output_proposal_v1(payment_proposal, block_index, enotes.front()); - return store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, block_index); + return store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, block_index, hf_version); } //------------------------------------------------------------------------------------------------------------------- bool try_load_carrot_coinbase_enote_from_transaction_v1(const cryptonote::transaction &tx, diff --git a/src/carrot_impl/format_utils.h b/src/carrot_impl/format_utils.h index a325b76..be315a5 100644 --- a/src/carrot_impl/format_utils.h +++ b/src/carrot_impl/format_utils.h @@ -149,7 +149,8 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( const std::vector &enotes, const cryptonote::blobdata &extra_nonce, const cryptonote::transaction_type &tx_type, - const std::uint64_t block_index); + const std::uint64_t block_index, + const std::uint8_t hf_version); /** * brief: make_single_enote_carrot_coinbase_transaction_v1 - store one coinbase Carrot enote to a cryptonote::transaction * param: destination - @@ -161,7 +162,8 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1( cryptonote::transaction make_single_enote_carrot_coinbase_transaction_v1(const CarrotDestinationV1 &destination, const rct::xmr_amount block_reward, const std::uint64_t block_index, - const cryptonote::blobdata &extra_nonce); + const cryptonote::blobdata &extra_nonce, + const std::uint8_t hf_version); /** * brief: try_load_carrot_coinbase_enote_from_transaction_v1 - load one coinbase Carrot enote from a cryptonote::transaction * param: tx - diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index bd1ac60..ccebbbf 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1501,16 +1501,14 @@ bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t heigh uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD; uint8_t hf_version_submitted = get_ideal_hard_fork_version(height - stake_lock_period - 1); - if (hf_version >= HF_VERSION_ENABLE_TOKENS) { - CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_ENABLE_TOKENS, false, "protocol transaction has wrong version"); - hf_version_submitted = hf_version; - } else if (hf_version == HF_VERSION_CARROT) { - if (hf_version_submitted >= HF_VERSION_CARROT || b.protocol_tx.vout.size() == 0) { - CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_CARROT, false, "protocol transaction has wrong version"); - } else { - CHECK_AND_ASSERT_MES(b.protocol_tx.version == 2, false, "protocol transaction has wrong version"); - } + if (hf_version >= HF_VERSION_CARROT) { + const uint8_t expected_protocol_version = + hf_version >= HF_VERSION_ENABLE_TOKENS ? TRANSACTION_VERSION_ENABLE_TOKENS : + ((hf_version_submitted >= HF_VERSION_CARROT || b.protocol_tx.vout.size() == 0) ? TRANSACTION_VERSION_CARROT : 2); + CHECK_AND_ASSERT_MES(b.protocol_tx.version == expected_protocol_version, false, "protocol transaction has wrong version"); CHECK_AND_ASSERT_MES(b.protocol_tx.type == cryptonote::transaction_type::PROTOCOL, false, "protocol transaction has wrong type"); + if (hf_version >= HF_VERSION_ENABLE_TOKENS) + hf_version_submitted = hf_version; } else { hf_version_submitted = hf_version; } @@ -1883,6 +1881,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, } CHECK_AND_ASSERT_MES(carrot_yield_payouts.empty(), false, "Carrot yield payouts require a Carrot protocol_tx"); + CHECK_AND_ASSERT_MES(create_token_count == 0, false, "CREATE_TOKEN protocol outputs require a Carrot protocol_tx"); // Merge the yield and audit payouts into an iterable vector std::vector> payouts{yield_payouts}; @@ -4059,6 +4058,8 @@ bool Blockchain::check_tx_asset_types(const transaction& tx, tx_verification_con } } else if (tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::CONVERT) { MERROR_VER("AUDIT and CONVERT transaction types are not allowed in this hardfork version:" << std::to_string(HF_VERSION_ENABLE_TOKENS)); + tvc.m_verifivation_failed = true; + return false; } else { MERROR_VER("Unknown transaction type: " << tx.type << "."); tvc.m_verifivation_failed = true; diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 0a8cf9f..6250209 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -346,7 +346,7 @@ namespace cryptonote // Clear the TX contents tx.set_null(); - tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? 3 : 2; + tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : 2; bool carrot_found = false; bool noncarrot_found = false; tx.type = cryptonote::transaction_type::PROTOCOL; @@ -390,9 +390,8 @@ namespace cryptonote memcpy(e.enote_ephemeral_pubkey.data, entry.return_pubkey.data, sizeof(crypto::public_key)); enotes.push_back(e); } - tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL, height); + tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL, height, hard_fork_version); tx.amount_burnt = 0; - tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT; tx.invalidate_hashes(); } catch (const std::exception &e) @@ -540,8 +539,7 @@ namespace cryptonote } } - tx = carrot::store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, height); - tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT; + tx = carrot::store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, height, hard_fork_version); tx.amount_burnt = stake_reward; tx.invalidate_hashes(); }