From ca2069facc8c4bc2dc863ea313fd7f8a4b3bf9fb Mon Sep 17 00:00:00 2001 From: akildemir Date: Fri, 27 Dec 2024 11:51:33 +0300 Subject: [PATCH 01/11] rewrite protocol tx construct/validate --- external/mx25519 | 1 + src/cryptonote_core/blockchain.cpp | 239 +++++--------------- src/cryptonote_core/blockchain.h | 3 +- src/cryptonote_core/cryptonote_tx_utils.cpp | 174 +------------- src/cryptonote_core/cryptonote_tx_utils.h | 2 +- src/cryptonote_core/tx_pool.cpp | 10 +- src/cryptonote_core/tx_pool.h | 5 +- 7 files changed, 65 insertions(+), 369 deletions(-) create mode 160000 external/mx25519 diff --git a/external/mx25519 b/external/mx25519 new file mode 160000 index 000000000..84ca1290f --- /dev/null +++ b/external/mx25519 @@ -0,0 +1 @@ +Subproject commit 84ca1290fa344351c95692f20f41a174b70e0c7b diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index a9d3be1fd..cfb48f14f 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1450,11 +1450,6 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version) { LOG_PRINT_L3("Blockchain::" << __func__); - if (!b.protocol_tx.vin.size()) { - // Nothing is created by this TX - check no money is included - CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "void protocol transaction in the block has outputs"); - return true; - } CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs"); CHECK_AND_ASSERT_MES(b.protocol_tx.vin[0].type() == typeid(txin_gen), false, "coinbase protocol transaction in the block has the wrong type"); CHECK_AND_ASSERT_MES(b.protocol_tx.version > 1, false, "Invalid coinbase protocol transaction version"); @@ -1531,176 +1526,74 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl } //------------------------------------------------------------------ // SRCG -bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, std::vector>& txs, uint8_t hf_version) +bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version) { LOG_PRINT_L3("Blockchain::" << __func__); - CHECK_AND_ASSERT_MES(b.tx_hashes.size() == txs.size(), false, "Invalid number of TXs / hashes supplied"); - if (!b.protocol_tx.vin.size()) { - // Nothing is created by this TX - check no money is included - CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "void protocol transaction in the block has outputs"); - return true; + // if nothing is created by this TX - check no money is included + size_t vout_size = b.protocol_tx.vout.size(); + CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs"); + CHECK_AND_ASSERT_MES(vout_size != 0, true, "coinbase protocol transaction in the block has no outputs"); + + // Can we have matured STAKE transactions yet? + uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD; + if (height <= stake_lock_period) { + return false; } - if (!b.protocol_tx.vout.size()) { - // No money is minted, nothing to verify - bail out - return true; + // Get the staking data for the block that matured this time + cryptonote::yield_block_info ybi_matured; + uint64_t matured_height = height - stake_lock_period - 1; + bool ok = get_ybi_entry(matured_height, ybi_matured); + if (!ok || ybi_matured.locked_coins_this_block == 0) { + LOG_ERROR("Block at height: " << height << " - Failed to obtain yield block information - aborting"); + return false; } - // Get the circulating supply so we can verify - std::map circ_supply; - if (hf_version >= HF_VERSION_ENABLE_CONVERT) { - circ_supply = get_db().get_circulating_supply(); + // Iterate over the cached data for block yield, calculating the yield payouts due + std::vector> yield_payouts; + if (!calculate_yield_payouts(matured_height, yield_payouts)) { + LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting"); + return false; } - - // Build a map of outputs from the protocol_tx - std::map> outputs; + + // go through each vout and validate for (auto& o : b.protocol_tx.vout) { + // gather the output data + uint64_t out_amount; + uint64_t out_unlock_time; + std::string out_asset_type; + crypto::public_key out_key; if (o.target.type() == typeid(txout_to_key)) { txout_to_key out = boost::get(o.target); - CHECK_AND_ASSERT_MES(out.unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output"); - CHECK_AND_ASSERT_MES(outputs.count(out.key) == 0, false, "Output duplicated in protocol_tx"); - outputs[out.key] = std::make_tuple(out.asset_type, o.amount, out.unlock_time); + out_unlock_time = out.unlock_time; + out_asset_type = out.asset_type; + out_key = out.key; + out_amount = o.amount; } else if (o.target.type() == typeid(txout_to_tagged_key)) { txout_to_tagged_key out = boost::get(o.target); - CHECK_AND_ASSERT_MES(out.unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output"); - CHECK_AND_ASSERT_MES(outputs.count(out.key) == 0, false, "Output duplicated in protocol_tx"); - outputs[out.key] = std::make_tuple(out.asset_type, o.amount, out.unlock_time); + out_unlock_time = out.unlock_time; + out_asset_type = out.asset_type; + out_key = out.key; + out_amount = o.amount; } else { MERROR("Block at height: " << height << " attempting to add protocol transaction with invalid type " << o.target.type().name()); return false; } - } - CHECK_AND_ASSERT_MES(outputs.size() == b.protocol_tx.vout.size(), false, "Mismatch between vout and outputs for protocol_tx - aborting"); - // Maintain a count of outputs that we have verified - std::vector outputs_verified; - - size_t tx_index = 0; - // Iterate over the block's transaction hashes, grabbing each - // from the tx_pool and validating them. - for (const auto& tx_tmp : txs) - { - // Get a ptr to the TX to simplify coding - const transaction* tx = &tx_tmp.first; - - // Check to see if the TX exists in the DB - this probably duplicates the effort in our caller, but better to be sure - if (m_db->tx_exists(tx->hash)) - { - MERROR("Block at height: " << height << " attempting to add transaction already in blockchain with id: " << tx->hash); + // check if there is entry in the yield payouts for this output + auto found = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair& p) { + return p.first.return_address == out_key; + }); + if (found == yield_payouts.end()) { + MERROR("Block at height: " << height << " - Failed to locate output for protocol TX - rejecting block"); return false; } - if (hf_version >= HF_VERSION_ENABLE_CONVERT) { - - // Check to see if the TX is a conversion or not - if (tx->type != cryptonote::transaction_type::CONVERT) { - // Only conversion (and failed conversion, aka refund) TXs need to be verified - skip this TX - continue; - } - - // Verify that the TX has an output in the protocol_tx to verify - if (outputs.count(tx->return_address) != 1) { - LOG_ERROR("Block at height: " << height << " - Failed to locate output for conversion TX id " << tx->hash << " - rejecting block"); - return false; - } - - // Get the output information - std::string output_asset_type; - uint64_t output_amount; - uint64_t output_unlock_time; - std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[tx->return_address]; - - // Verify the asset_type - if (tx->source_asset_type == output_asset_type) { - // Check the amount for REFUND - if (tx->amount_burnt != output_amount) { - LOG_ERROR("Block at height: " << height << " - Output amount does not match amount_burnt for refunded TX id " << tx->hash << " - rejecting block"); - return false; - } - - // Verified the refund successfully - outputs_verified.push_back(tx->return_address); - - } else if (tx->destination_asset_type == output_asset_type) { - // Check the amount for CONVERT - - // Verify the amount of the conversion - uint64_t amount_minted_check = 0, amount_slippage_check = 0; - bool ok = cryptonote::calculate_conversion(tx->source_asset_type, tx->destination_asset_type, tx->amount_burnt, tx->amount_slippage_limit, amount_minted_check, amount_slippage_check, circ_supply, b.pricing_record, hf_version); - if (!ok) { - LOG_ERROR("Block at height: " << height << " - Failed to calculate conversion for TX id " << tx->hash << " - rejecting block"); - return false; - } - if (amount_minted_check != output_amount) { - LOG_ERROR("Block at height: " << height << " - Output amount does not match amount minted for converted TX id " << tx->hash << " - rejecting block"); - return false; - } - - // Verified the conversion successfully - outputs_verified.push_back(tx->return_address); - - } else { - LOG_ERROR("Block at height: " << height << " - Output asset type incorrect: source " << tx->source_asset_type << ", dest " << tx->destination_asset_type << ", got " << output_asset_type << " - rejecting block"); - return false; - } - } - } - - // Can we have matured STAKE transactions yet? - uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD; - if (height > stake_lock_period) { - - // Yes - Get the staking data for the block that matured this time - cryptonote::yield_block_info ybi_matured; - uint64_t matured_height = height - stake_lock_period - 1; - bool ok = get_ybi_entry(matured_height, ybi_matured); - if (ok && ybi_matured.locked_coins_this_block > 0) { - - // Iterate over the cached data for block yield, calculating the yield payouts due - std::vector> yield_payouts; - if (!calculate_yield_payouts(matured_height, yield_payouts)) { - LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting"); - return false; - } - - // Iterate the yield payouts, verifying as we go - for (const auto& payout: yield_payouts) { - - // Do we have a singular matching output in tx.vout? - if (outputs.count(payout.first.return_address) != 1) { - LOG_ERROR("Block at height: " << height << " - Failed to locate output for matured TX id " << payout.first.tx_hash << " - rejecting block"); - return false; - } - - // Get the output information - std::string output_asset_type; - uint64_t output_amount; - uint64_t output_unlock_time; - std::tie(output_asset_type, output_amount, output_unlock_time) = outputs[payout.first.return_address]; - - // Verify the asset type - must be SAL - if (output_asset_type != "SAL") { - LOG_ERROR("Block at height: " << height << " - Incorrect output asset type for matured TX id " << payout.first.tx_hash << " - rejecting block"); - return false; - } - - // Verify the amount - if (output_amount != payout.second) { - LOG_ERROR("Block at height: " << height << " - Incorrect output amount for matured TX id " << payout.first.tx_hash << " - rejecting block"); - return false; - } - - // Amount and return_address match our expectation - outputs_verified.push_back(payout.first.return_address); - } - } - } - - // All candidates have been evaluated - make sure there are no other outputs that have not been catered for - if (outputs.size() != outputs_verified.size()) { - LOG_ERROR("Block at height: " << height << " - Incorrect number of outputs - expected " << outputs_verified.size() << " but received " << outputs.size() << " - rejecting block"); - return false; + // check other fields + CHECK_AND_ASSERT_MES(out_unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid unlock time on protocol_tx output"); + CHECK_AND_ASSERT_MES(out_asset_type == "SAL", false, "Incorrect output asset type for protocol TX"); + CHECK_AND_ASSERT_MES(out_amount == found->second, false, "Incorrect output amount for protocol TX"); } // Everything checks out @@ -1955,46 +1848,16 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, size_t txs_weight; uint64_t fee; - /** - * Here is where the magic happens - determination of the payments for the protocol_tx - * - * We need to know the following: - * - address to send the funds to ("return_address") - * - asset_type being burnt - * - amount being burnt - * - asset_type being minted - * - * (All of this information should be provided by the txpool_tx_meta_t object) - * - * From that little lot, we can hopefully work out the slippage on all of the TXs, and - * therefore the amount to be minted for each TX, and who to pay it to, etc, etc. - */ - std::vector protocol_metadata; - std::vector protocol_entries; - if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, b.major_version, b.pricing_record, circ_supply, protocol_metadata)) + if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, b.major_version)) { return false; } - - // Clone the txpool_tx_meta_t data into a more useable format - for (auto& meta: protocol_metadata) { - cryptonote::protocol_data_entry entry; - entry.amount_burnt = meta.amount_burnt; - entry.amount_minted = 0; - entry.amount_slippage_limit = meta.amount_slippage_limit; - entry.source_asset = asset_type_from_id(meta.source_asset_id); - entry.destination_asset = asset_type_from_id(meta.destination_asset_id); - entry.return_address = meta.return_address; - entry.type = meta.tx_type; - entry.P_change = meta.one_time_public_key; - entry.return_pubkey = meta.return_pubkey; - protocol_entries.push_back(entry); - } // Check to see if there are any matured YIELD TXs uint64_t yield_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD; uint64_t start_height = (height > yield_lock_period) ? height - yield_lock_period - 1 : 0; + std::vector protocol_entries; cryptonote::yield_block_info ybi_matured; bool ok = get_ybi_entry(start_height, ybi_matured); if (ok && ybi_matured.locked_coins_this_block > 0) { @@ -2027,7 +1890,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, address_parse_info treasury_address_info; ok = cryptonote::get_account_address_from_str(treasury_address_info, m_nettype, get_config(m_nettype).TREASURY_ADDRESS); CHECK_AND_ASSERT_MES(ok, false, "Failed to obtain treasury address info"); - ok = construct_protocol_tx(height, protocol_fee, b.protocol_tx, protocol_entries, circ_supply, b.pricing_record, miner_address, treasury_address_info.address, b.major_version); + ok = construct_protocol_tx(height, b.protocol_tx, protocol_entries, b.major_version); CHECK_AND_ASSERT_MES(ok, false, "Failed to construct protocol tx"); pool_cookie = m_tx_pool.cookie(); @@ -5027,7 +4890,7 @@ leave: TIME_MEASURE_FINISH(vmt); TIME_MEASURE_START(vpt); - if(!validate_protocol_transaction(bl, blockchain_height, txs, m_hardfork->get_current_version())) + if(!validate_protocol_transaction(bl, blockchain_height, m_hardfork->get_current_version())) { MERROR_VER("Block with id: " << id << " has incorrect protocol transaction"); bvc.m_verifivation_failed = true; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 9afbbfefc..a86dac5eb 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -1529,12 +1529,11 @@ namespace cryptonote * * @param b the block containing the miner transaction to be validated * @param height the blockchain's weight - * @param txs a vector containing all the TXs and their blobs, needed to obtain tx_types, asset_types and burnt amounts * @param version hard fork version for that transaction * * @return false if anything is found wrong with the protocol transaction, otherwise true */ - bool validate_protocol_transaction(const block& b, uint64_t height, std::vector>& txs, uint8_t hf_version); + bool validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version); /** * @brief reverts the blockchain to its previous state following a failed switch diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 383dfd199..c122c2d05 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -333,18 +333,12 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool construct_protocol_tx(const size_t height, - uint64_t& protocol_fee, - transaction& tx, - std::vector& protocol_data, - std::map circ_supply, - const oracle::pricing_record& pr, - const account_public_address &miner_address, - const account_public_address &treasury_address, - const uint8_t hf_version) { - - // A vector to contain all of the additional _tx_secret_keys_ - //std::vector& additional_tx_keys; + bool construct_protocol_tx( + const size_t height, + transaction& tx, + std::vector& protocol_data, + const uint8_t hf_version + ) { // Clear the TX contents tx.set_null(); @@ -358,174 +352,24 @@ namespace cryptonote if (!sort_tx_extra(tx.extra, tx.extra)) return false; - // Update the circulating_supply information, while keeping a count of amount to be created using txin_gen - std::map txin_gen_totals; - uint64_t txin_gen_final = 0; - for (auto const& entry: protocol_data) { - if (!circ_supply.count(entry.source_asset)) { - LOG_ERROR("Circulating supply does not have " << entry.source_asset << " balance - invalid source_asset"); - return false; - } - // Deduct the amount_burnt from the circulating_supply balance - circ_supply[entry.source_asset] -= entry.amount_burnt; - } - - // Calculate the slippage for the output amounts LOG_PRINT_L2("Creating protocol_tx..."); - uint64_t slippage_total = 0; std::vector additional_tx_public_keys; for (auto const& entry: protocol_data) { - if (entry.destination_asset == "BURN") { - // BURN TX - no slippage, no money minted - skip - continue; - } - // CONVERT TX - /* - // Create a secret TX key (= s) - crypto::secret_key s = keypair::generate(hw::get_device("default")).sec; - //additional_tx_keys.push_back(s); - - // Now add the correct TX public key (= sP_change) - // This has to be done using smK() call because of g_k_d() performing a torsion clear - crypto::public_key txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(entry.P_change), rct::sk2rct(s))); - additional_tx_public_keys.push_back(txkey_pub); - - // Calculate the actual return address, because the field we already have is actually the TX pubkey to use - // return address = Hs(syF || i)G + P_change = Hs(saP_change || i)G + P_change - // Generate the uniqueness for the input - size_t output_index = tx.vout.size(); - - // y = Hs(uniqueness) - ec_scalar y; - CHECK_AND_ASSERT_MES(cryptonote::calculate_uniqueness((cryptonote::transaction_type)(entry.type), entry.input_k_image, height, 0, y), false, "while creating protocol_tx outs: failed to calculate uniqueness"); - - rct::key key_y = (rct::key&)(y); - rct::key key_F = (rct::key&)(entry.return_address); - crypto::public_key syF = rct::rct2pk(rct::scalarmultKey(rct::scalarmultKey(key_F, key_y), rct::sk2rct(s))); - crypto::key_derivation derivation_syF = AUTO_VAL_INIT(derivation_syF); - std::memcpy(derivation_syF.data, syF.data, sizeof(crypto::key_derivation)); - - crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); - bool r = crypto::derive_public_key(derivation_syF, output_index, entry.P_change, out_eph_public_key); - CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_public_key(" << derivation_syF << ", " << key_y << ", "<< entry.P_change << ")"); - - // Sanity checks - crypto::public_key P_change_verify = crypto::null_pkey; - r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation_syF, output_index, P_change_verify); - CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed sanity check calling derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation_syF << ", " << key_y << ", " << P_change_verify << ")"); - CHECK_AND_ASSERT_MES(entry.P_change == P_change_verify, false, "while creating protocol_tx outs: failed sanity check (keys do not match)"); - */ - /* - LOG_ERROR("***************************************************************************************"); - LOG_ERROR("output_index : " << output_index); - LOG_ERROR("P_change : " << entry.P_change); - LOG_ERROR("key_y : " << key_y); - LOG_ERROR("key_F : " << key_F); - LOG_ERROR("s : " << s); - LOG_ERROR("der. (syF) : " << derivation_syF); - LOG_ERROR("txkey_pub : " << txkey_pub); - LOG_ERROR("output_key : " << out_eph_public_key << " (derivation_syF, output_index, P_change)"); - LOG_ERROR("P_change_ver : " << P_change_verify); - LOG_ERROR("***************************************************************************************"); - */ - - if (entry.type == cryptonote::transaction_type::CONVERT) { - - // Now calculate the slippage, and decide if it is going to be converted or refunded - uint64_t amount_slippage = 0, amount_minted = 0; - bool ok = cryptonote::calculate_conversion(entry.source_asset, entry.destination_asset, entry.amount_burnt, entry.amount_slippage_limit, amount_minted, amount_slippage, circ_supply, pr, hf_version); - if (!ok) { - LOG_ERROR("failed to calculate slippage when trying to build protocol_tx"); - return false; - } - if (amount_minted == 0) { - - // REFUND - LOG_PRINT_L2("Conversion TX refunded - slippage too high"); - txin_gen_totals[entry.source_asset] += entry.amount_burnt; - - // Create the TX output for this refund - tx_out out; - //cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out); - cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out); - additional_tx_public_keys.push_back(entry.return_pubkey); - tx.vout.push_back(out); - } else { - - // CONVERTED - LOG_PRINT_L2("Conversion TX submitted - converted " << print_money(entry.amount_burnt) << " " << entry.source_asset << " to " << print_money(amount_minted) << " " << entry.destination_asset << "(slippage " << print_money(amount_slippage) << ")"); - txin_gen_totals[entry.destination_asset] += amount_minted; - - // Add the slippage to our total for the block - if (entry.source_asset == "SAL") { - slippage_total += amount_slippage; - } else { - // Convert the slippage into a SAL amount so we can pay a proportion to the miner - uint64_t conversion_rate = 0, amount_slippage_converted = 0; - ok = get_conversion_rate(pr, entry.source_asset, entry.destination_asset, conversion_rate); - CHECK_AND_ASSERT_MES(ok, false, "Failed to get conversion rate for miner payout"); - ok = get_converted_amount(conversion_rate, amount_slippage, amount_slippage_converted); - CHECK_AND_ASSERT_MES(ok, false, "Failed to get converted slippage amount for miner payout"); - slippage_total += amount_slippage_converted; - } - - // Create the TX output for this conversion - tx_out out; - //cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out); - cryptonote::set_tx_out(amount_minted, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out); - additional_tx_public_keys.push_back(entry.return_pubkey); - tx.vout.push_back(out); - } - } else if (entry.type == cryptonote::transaction_type::STAKE) { - + if (entry.type == cryptonote::transaction_type::STAKE) { // PAYOUT LOG_PRINT_L2("Yield TX payout submitted " << entry.amount_burnt << entry.source_asset); - txin_gen_totals[entry.source_asset] += entry.amount_burnt; - + // Create the TX output for this refund tx_out out; - //cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out); cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out); additional_tx_public_keys.push_back(entry.return_pubkey); tx.vout.push_back(out); } } - + // Add in all of the additional TX pubkeys we need to process the payments add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys); - if (slippage_total > 0) { - - // Add a payout for the miner - uint64_t slippage_miner = slippage_total / 5; - - crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); - crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); - bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation); - CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{txkey.sec} << ")"); - - r = crypto::derive_public_key(derivation, tx.vout.size(), miner_address.m_spend_public_key, out_eph_public_key); - CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")"); - - tx_out out_miner; - cryptonote::set_tx_out(slippage_miner, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, false, crypto::view_tag{}, out_miner); - tx.vout.push_back(out_miner); - - // Add a payout for the treasury - crypto::key_derivation derivation_treasury = AUTO_VAL_INIT(derivation_treasury); - crypto::public_key out_eph_public_key_treasury = AUTO_VAL_INIT(out_eph_public_key_treasury); - r = crypto::generate_key_derivation(treasury_address.m_view_public_key, txkey.sec, derivation_treasury); - CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << treasury_address.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{txkey.sec} << ")"); - - r = crypto::derive_public_key(derivation_treasury, tx.vout.size(), treasury_address.m_spend_public_key, out_eph_public_key_treasury); - CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")"); - - uint64_t slippage_treasury = slippage_miner >> 1; - tx_out out_treasury; - cryptonote::set_tx_out(slippage_treasury, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key_treasury, false, crypto::view_tag{}, out_treasury); - tx.vout.push_back(out_treasury); - } - // Create the txin_gen now txin_gen in; in.height = height; diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index f7bf7dac4..2b91c3d3b 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -67,7 +67,7 @@ namespace cryptonote }; //--------------------------------------------------------------- - bool construct_protocol_tx(const size_t height, uint64_t& protocol_fee, transaction& tx, std::vector& protocol_data, std::map circ_supply, const oracle::pricing_record& pr, const account_public_address &miner_address, const account_public_address &treasury_address, const uint8_t hf_version); + bool construct_protocol_tx(const size_t height, transaction& tx, std::vector& protocol_data, const uint8_t hf_version); //--------------------------------------------------------------- bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1); diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index aaed85ad1..382838861 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -1614,7 +1614,7 @@ namespace cryptonote //--------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- //TODO: investigate whether boolean return is appropriate - bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version, oracle::pricing_record& pr, std::map& circ_supply, std::vector& protocol_metadata) + bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version) { CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL1(m_blockchain); @@ -1744,14 +1744,6 @@ namespace cryptonote continue; } - // Check what the TX type is - only CONVERT needs a cash_value - if (meta.source_asset_id == meta.destination_asset_id) { - // TRANSFER - } else { - // BURN OR CONVERT (both require inclusion in the protocol_tx calculation for circ_supply purposes) - protocol_metadata.push_back(meta); - } - bl.tx_hashes.push_back(sorted_it->second); total_weight += meta.weight; fee += meta.fee; diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 24c624c1a..0b279ee5a 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -227,13 +227,10 @@ namespace cryptonote * @param fee return-by-reference the total of fees from the included transactions * @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees * @param version hard fork version to use for consensus rules - * @param pr the current pricing record - * @param circ_cupply the circulating supply information for all asset types - * @param protocol_metadata the TX-specific data needed to create conversion outputs in the protocol TX (including converted amounts and refunds) * * @return true */ - bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version, oracle::pricing_record& pr, std::map& circ_supply, std::vector& protocol_metadata); + bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version); /** * @brief get a list of all transactions in the pool From e9a2b6fbb7f933fd345a48f9f98eb53a5d9a04e2 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Fri, 27 Dec 2024 15:36:41 +0000 Subject: [PATCH 02/11] additional checks needed for protocol_tx validation --- src/cryptonote_core/blockchain.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index cfb48f14f..54c88b4d0 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1450,6 +1450,13 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version) { LOG_PRINT_L3("Blockchain::" << __func__); + if (height == 0) { + // Genesis block exception + CHECK_AND_ASSERT_MES(b.protocol_tx.version == 1, false, "Invalid genesis protocol transaction version"); + CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 0, false, "genesis protocol transaction in the block has inputs"); + CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "genesis protocol transaction in the block has outputs"); + return true; + } CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs"); CHECK_AND_ASSERT_MES(b.protocol_tx.vin[0].type() == typeid(txin_gen), false, "coinbase protocol transaction in the block has the wrong type"); CHECK_AND_ASSERT_MES(b.protocol_tx.version > 1, false, "Invalid coinbase protocol transaction version"); @@ -1530,6 +1537,14 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, { LOG_PRINT_L3("Blockchain::" << __func__); + if (height == 0) { + // Genesis block exception + CHECK_AND_ASSERT_MES(b.protocol_tx.version == 1, false, "Invalid genesis protocol transaction version"); + CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 0, false, "genesis protocol transaction in the block has inputs"); + CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == 0, false, "genesis protocol transaction in the block has outputs"); + return true; + } + // if nothing is created by this TX - check no money is included size_t vout_size = b.protocol_tx.vout.size(); CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs"); @@ -1557,7 +1572,11 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, return false; } + // Check we have the correct number of entries + CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting"); + // go through each vout and validate + std::set used_keys; for (auto& o : b.protocol_tx.vout) { // gather the output data uint64_t out_amount; @@ -1581,6 +1600,15 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, return false; } + // Check if key has already been seen + if (used_keys.count(out_key) != 0) { + LOG_ERROR("Block at height: " << height << " - Duplicated output key " << out_key << " for protocol TX - aborting"); + return false; + } + + // Add key to list of already-seen + used_keys.insert(out_key); + // check if there is entry in the yield payouts for this output auto found = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair& p) { return p.first.return_address == out_key; From 64a69268fe7969ec5a40dc94de38d9976114cb46 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Fri, 31 Jan 2025 15:10:13 +0000 Subject: [PATCH 03/11] set hard fork 6 height; bumped version number --- README.md | 2 +- src/hardforks/hardforks.cpp | 3 +++ src/version.cpp.in | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aa8788b59..09c19914e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salvium Zero v0.9.0-rc10 +# Salvium Zero v0.9.0 Copyright (c) 2023-2024, Salvium Portions Copyright (c) 2014-2023, The Monero Project diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp index 2ff578c5f..c4cb93f46 100644 --- a/src/hardforks/hardforks.cpp +++ b/src/hardforks/hardforks.cpp @@ -46,6 +46,9 @@ const hardfork_t mainnet_hard_forks[] = { // version 5 starts from block 136100, which is on or around the 9th of January, 2025. Fork time finalised on 2025-01-08. No fork voting occurs for the v5 fork. { 5, 136100, 0, 1736265945 }, + + // version 6 starts from block 154750, which is on or around the 4th of February, 2025. Fork time finalised on 2025-01-31. No fork voting occurs for the v6 fork. + { 6, 154750, 0, 1738336000 }, }; const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1); diff --git a/src/version.cpp.in b/src/version.cpp.in index b043c6362..04dbe9a4a 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "0.9.0-rc10" +#define DEF_SALVIUM_VERSION "0.9.0" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.3" #define DEF_MONERO_RELEASE_NAME "Zero" From 19be3a6146a7490de7fb8d39601cf86a7aa80243 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Fri, 31 Jan 2025 17:20:52 +0000 Subject: [PATCH 04/11] fixed gitignore issue with CMake and audit tool --- src/blockchain_utilities/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt index c09de09a1..a89b64de9 100644 --- a/src/blockchain_utilities/CMakeLists.txt +++ b/src/blockchain_utilities/CMakeLists.txt @@ -152,7 +152,7 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTO monero_private_headers(blockchain_audit ${blockchain_audit_private_headers}) else() - message(FATAL_ERROR "blockchain_audit.cpp not found - not building the audit tool") + message(STATUS "blockchain_audit.cpp not found - not building the audit tool") endif() monero_add_executable(blockchain_import From ee586a3fcaaa5fa3b83ef1d91093e053710bfb47 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Tue, 4 Feb 2025 10:09:49 +0000 Subject: [PATCH 05/11] added asset_type check - sorry, sneaky hackers, but you have a spy in your midst ;) --- README.md | 10 +++++----- src/blockchain_db/lmdb/db_lmdb.cpp | 2 +- src/cryptonote_core/blockchain.cpp | 14 ++++++++++++++ src/version.cpp.in | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 09c19914e..ad6f46d4f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salvium Zero v0.9.0 +# Salvium Zero v0.9.1 Copyright (c) 2023-2024, Salvium Portions Copyright (c) 2014-2023, The Monero Project @@ -172,7 +172,7 @@ invokes cmake commands as needed. ```bash cd salvium - git checkout v0.9.0 + git checkout v0.9.1 make ``` @@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( ```bash git clone https://github.com/salvium/salvium cd salvium - git checkout v0.9.0 + git checkout v0.9.1 ``` * Build: @@ -370,10 +370,10 @@ application. cd salvium ``` -* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.0'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.1'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.9.0 + git checkout v0.9.1 ``` * If you are on a 64-bit system, run: diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index e290832ab..935bfb1e2 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -215,7 +215,7 @@ namespace * yield_block_data block height {slippage_coins, locked_coins, lc_total, network_health} * yield_tx_data block height {txn hash, locked_coins, return_address} * - * audit_data block height {locked_coins, lc_total} + * audit_block_data block height {locked_coins, lc_total} * audit_tx_data block height {txn hash, locked_coins, return_address} * * Note: where the data items are of uniform size, DUPFIXED tables have diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index c5aab80e5..dbb5457ba 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3951,6 +3951,20 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, } } + if (tx.type == cryptonote::transaction_type::AUDIT) { + // Make sure we are supposed to accept AUDIT txs at this point + const std::map> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS; + CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork"); + std::string expected_asset_type = audit_hard_forks.at(hf_version).first; + CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX"); + } else { + if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) { + CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL1", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX"); + } else { + CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX"); + } + } + std::vector> pubkeys(tx.vin.size()); std::vector < uint64_t > results; results.resize(tx.vin.size(), 0); diff --git a/src/version.cpp.in b/src/version.cpp.in index 04dbe9a4a..bfd9dc5b3 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "0.9.0" +#define DEF_SALVIUM_VERSION "0.9.1" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.3" #define DEF_MONERO_RELEASE_NAME "Zero" From 8bf35db67ed03df1f8d12055a4771e932e159cf3 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Tue, 4 Feb 2025 10:40:49 +0000 Subject: [PATCH 06/11] fixed submodules that got merged incorrectly --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitmodules b/.gitmodules index 7e00da228..68faaf9fd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,3 +14,6 @@ [submodule "external/miniupnp"] path = external/miniupnp url = https://github.com/miniupnp/miniupnp +[submodule "external/mx25519"] + path = external/mx25519 + url = https://github.com/tevador/mx25519 From eb9f799b8b85c0b6f4a2f38ea0f4ced92c1f9abb Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Mon, 10 Feb 2025 13:11:52 +0000 Subject: [PATCH 07/11] fixed syncing message error level; added thread library for auditing --- src/blockchain_utilities/CMakeLists.txt | 8 +++- src/blockchain_utilities/threadpool_boost.cpp | 44 +++++++++++++++++++ src/blockchain_utilities/threadpool_boost.h | 24 ++++++++++ src/cryptonote_core/blockchain.cpp | 9 ++-- 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/blockchain_utilities/threadpool_boost.cpp create mode 100644 src/blockchain_utilities/threadpool_boost.h diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt index a89b64de9..ab7130277 100644 --- a/src/blockchain_utilities/CMakeLists.txt +++ b/src/blockchain_utilities/CMakeLists.txt @@ -145,9 +145,12 @@ monero_private_headers(blockchain_scanner if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp") set(blockchain_audit_sources blockchain_audit.cpp + threadpool_boost.cpp ) - set(blockchain_audit_private_headers) + set(blockchain_audit_private_headers + threadpool_boost.h + ) monero_private_headers(blockchain_audit ${blockchain_audit_private_headers}) @@ -329,6 +332,8 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTO ${blockchain_audit_sources} ${blockchain_audit_private_headers}) + target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc) + target_link_libraries(blockchain_audit PRIVATE wallet @@ -338,6 +343,7 @@ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTO blockchain_db version epee + mysqlcppconn ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} diff --git a/src/blockchain_utilities/threadpool_boost.cpp b/src/blockchain_utilities/threadpool_boost.cpp new file mode 100644 index 000000000..264d1d97a --- /dev/null +++ b/src/blockchain_utilities/threadpool_boost.cpp @@ -0,0 +1,44 @@ +#include +#include "threadpool_boost.h" + +ThreadPool::ThreadPool(size_t numThreads) + : workGuard(boost::asio::make_work_guard(ioService)) { + for (size_t i = 0; i < numThreads; ++i) { + workers.emplace_back([this]() { + std::cerr << "Thread started" << std::endl; + ioService.run(); + std::cerr << "Thread finished" << std::endl; + }); + } +} + +void ThreadPool::enqueue(std::function task) { + ioService.post([task]() { + try { + task(); // Run the task + } catch (const std::exception& e) { + std::cerr << "Exception in thread pool task: " << e.what() << std::endl; + } catch (...) { + std::cerr << "Unknown exception in thread pool task!" << std::endl; + } + }); +} + +bool ThreadPool::isStopping() const { + return ioService.stopped(); // Check if io_context has stopped +} + +void ThreadPool::waitForCompletion() { + std::cout << "Waiting for completion...\n"; + workGuard.reset(); // Allow ioService to stop when no more tasks + ioService.run(); // Ensure no threads are left hanging + + for (auto &worker : workers) { + if (worker.joinable()) worker.join(); + } + std::cout << "All threads joined.\n"; +} + +ThreadPool::~ThreadPool() { + waitForCompletion(); +} diff --git a/src/blockchain_utilities/threadpool_boost.h b/src/blockchain_utilities/threadpool_boost.h new file mode 100644 index 000000000..bbcc01704 --- /dev/null +++ b/src/blockchain_utilities/threadpool_boost.h @@ -0,0 +1,24 @@ +#ifndef THREADPOOL_BOOST_H +#define THREADPOOL_BOOST_H + +#include +#include +#include +#include + +class ThreadPool { +public: + explicit ThreadPool(size_t numThreads); + ~ThreadPool(); + + void enqueue(std::function task); + bool isStopping() const; + void waitForCompletion(); + +private: + boost::asio::io_service ioService; + boost::asio::executor_work_guard workGuard; + std::vector workers; +}; + +#endif // THREADPOOL_BOOST_H diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 52db3fb8e..f37af7261 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1550,10 +1550,13 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height, } // if nothing is created by this TX - check no money is included - size_t vout_size = b.protocol_tx.vout.size(); CHECK_AND_ASSERT_MES(b.protocol_tx.vin.size() == 1, false, "coinbase protocol transaction in the block has no inputs"); - CHECK_AND_ASSERT_MES(vout_size != 0, true, "coinbase protocol transaction in the block has no outputs"); - + size_t vout_size = b.protocol_tx.vout.size(); + if (vout_size == 0) { + LOG_PRINT_L2("coinbase protocol transaction in the block has no outputs"); + return true; + } + // Can we have matured STAKE transactions yet? uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD; if (height <= stake_lock_period) { From b298f542a645219a73eb452732ad6dbcf95c9e89 Mon Sep 17 00:00:00 2001 From: akildemir <34187742+akildemir@users.noreply.github.com> Date: Mon, 10 Feb 2025 16:20:42 +0300 Subject: [PATCH 08/11] add audit tx support for wallet api (#14) --- src/wallet/api/wallet.cpp | 28 ++++++++++++++++++++++++++++ src/wallet/api/wallet.h | 4 ++++ src/wallet/api/wallet2_api.h | 19 +++++++++++++++++-- src/wallet/api/yield_info.cpp | 2 +- src/wallet/api/yield_info.h | 4 ++-- 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 94b0c19ea..8ba862609 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1444,6 +1444,34 @@ PendingTransaction *WalletImpl::createStakeTransaction(uint64_t amount, uint32_t return createTransactionMultDest(Monero::transaction_type::STAKE, std::vector {dst_addr}, payment_id, amount ? (std::vector {amount}) : (optional>()), mixin_count, asset_type, is_return, priority, subaddr_account, subaddr_indices); } +PendingTransaction *WalletImpl::createAuditTransaction( + uint32_t mixin_count, + PendingTransaction::Priority priority, + uint32_t subaddr_account, + std::set subaddr_indices +) { + // Need to populate {dst_entr, payment_id, asset_type, is_return} + const string dst_addr = m_wallet->get_subaddress_as_str({subaddr_account, 0});//MY LOCAL (SUB)ADDRESS + const string payment_id = ""; + const string asset_type = "SAL"; + const bool is_return = false; + + LOG_ERROR("createAuditTransaction: called"); + + return createTransactionMultDest( + Monero::transaction_type::AUDIT, + std::vector {dst_addr}, + payment_id, + (optional>()), + mixin_count, + asset_type, + is_return, + priority, + subaddr_account, + subaddr_indices + ); +} + // TODO: // 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) // 2 - check / design how "Transaction" can be single interface diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 709bb8df1..cfdf13779 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -158,6 +158,10 @@ public: PendingTransaction::Priority priority = PendingTransaction::Priority_Low, uint32_t subaddr_account = 0, std::set subaddr_indices = {}) override; + PendingTransaction * createAuditTransaction(uint32_t mixin_count, + PendingTransaction::Priority priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}) override; PendingTransaction * createTransactionMultDest(const transaction_type &tx_type, const std::vector &dst_addr, const std::string &payment_id, optional> amount, uint32_t mixin_count, diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index 2605f4754..071142d8d 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -58,7 +58,8 @@ enum transaction_type : uint8_t { BURN = 5, STAKE = 6, RETURN = 7, - MAX = 7 + AUDIT = 8, + MAX = 8 }; namespace Utils { @@ -97,7 +98,7 @@ struct YieldInfo virtual uint64_t yield() const = 0; virtual uint64_t yield_per_stake() const = 0; virtual std::string period() const = 0; - virtual std::vector> payouts() const = 0; + virtual std::vector> payouts() const = 0; }; @@ -878,6 +879,20 @@ struct Wallet uint32_t subaddr_account = 0, std::set subaddr_indices = {}) = 0; + /*! + * \brief createAuditTransaction creates audit transaction. + * \param mixin_count mixin count. if 0 passed, wallet will use default value + * \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices + * \param priority + * \return PendingTransaction object. caller is responsible to check PendingTransaction::status() + * after object returned + */ + + virtual PendingTransaction * createAuditTransaction(uint32_t mixin_count, + PendingTransaction::Priority = PendingTransaction::Priority_Low, + uint32_t subaddr_account = 0, + std::set subaddr_indices = {}) = 0; + /*! * \brief createTransactionMultDest creates transaction with multiple destinations. if dst_addr is an integrated address, payment_id is ignored * \param tx_type the type of transaction being created diff --git a/src/wallet/api/yield_info.cpp b/src/wallet/api/yield_info.cpp index 9ff401534..0780b349e 100644 --- a/src/wallet/api/yield_info.cpp +++ b/src/wallet/api/yield_info.cpp @@ -123,7 +123,7 @@ namespace Monero { return m_yield_per_stake; } - std::vector> YieldInfoImpl::payouts() const + std::vector> YieldInfoImpl::payouts() const { return m_payouts; } diff --git a/src/wallet/api/yield_info.h b/src/wallet/api/yield_info.h index 8ec98fb42..ae08c4f9b 100644 --- a/src/wallet/api/yield_info.h +++ b/src/wallet/api/yield_info.h @@ -53,7 +53,7 @@ public: uint64_t yield() const override; uint64_t yield_per_stake() const override; std::string period() const override; - std::vector> payouts() const override; + std::vector> payouts() const override; private: friend class WalletImpl; @@ -68,7 +68,7 @@ private: uint64_t m_yield_per_stake; uint64_t m_num_entries; std::string m_period; - std::vector> m_payouts; + std::vector> m_payouts; }; } From 6889321361818571ab3211715462c9893360d8e1 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Tue, 11 Feb 2025 12:18:08 +0000 Subject: [PATCH 09/11] fixed possible throw() when dust in index=0; bumped version number --- README.md | 10 +++++----- src/cryptonote_core/blockchain.cpp | 4 +++- src/hardforks/hardforks.cpp | 8 +++++++- src/simplewallet/simplewallet.cpp | 22 ++++++++++++++++------ src/version.cpp.in | 2 +- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ad6f46d4f..5f08cfc2b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salvium Zero v0.9.1 +# Salvium Zero v0.9.2 Copyright (c) 2023-2024, Salvium Portions Copyright (c) 2014-2023, The Monero Project @@ -172,7 +172,7 @@ invokes cmake commands as needed. ```bash cd salvium - git checkout v0.9.1 + git checkout v0.9.2 make ``` @@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( ```bash git clone https://github.com/salvium/salvium cd salvium - git checkout v0.9.1 + git checkout v0.9.2 ``` * Build: @@ -370,10 +370,10 @@ application. cd salvium ``` -* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.1'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.2'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.9.1 + git checkout v0.9.2 ``` * If you are on a 64-bit system, run: diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index f37af7261..0ac692224 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -4514,7 +4514,9 @@ bool Blockchain::calculate_audit_payouts(const uint64_t start_height, std::vecto } // Build a blacklist of staking TXs _not_ to pay out for - const std::set txs_blacklist = {}; + const std::set txs_blacklist = { + "017a79539e69ce16e91d9aa2267c102f336678c41636567c1129e3e72149499a" + }; // Get the ABI information for the 21,600 blocks that the matured TX(s), we can calculate audit for (const auto& entry: audit_entries) { diff --git a/src/hardforks/hardforks.cpp b/src/hardforks/hardforks.cpp index c4cb93f46..9a5d3b2c3 100644 --- a/src/hardforks/hardforks.cpp +++ b/src/hardforks/hardforks.cpp @@ -49,6 +49,9 @@ const hardfork_t mainnet_hard_forks[] = { // version 6 starts from block 154750, which is on or around the 4th of February, 2025. Fork time finalised on 2025-01-31. No fork voting occurs for the v6 fork. { 6, 154750, 0, 1738336000 }, + + // version 7 starts from block 161900, which is on or around the 14th of February, 2025. Fork time finalised on 2025-02-04. No fork voting occurs for the v7 fork. + { 7, 161900, 0, 1739264400 }, }; const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1); @@ -69,8 +72,11 @@ const hardfork_t testnet_hard_forks[] = { // version 5 (TX shutdown) starts from block 800 { 5, 800, 0, 1734607005 }, - // version 6 (audit) starts from block 815 + // version 6 (audit 1) starts from block 815 { 6, 815, 0, 1734608000 }, + + // version 7 (audit 1 pause) starts from block 900 + { 7, 900, 0, 1739264400 }, }; const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 56cb394c3..38c587989 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6981,12 +6981,22 @@ bool simple_wallet::transfer_main( // Skip this wallet if there is no balance unlocked to audit if (unlocked_balance_per_subaddr.count(subaddr_index) == 0) continue; - - std::set subaddr_indices_single; - subaddr_indices_single.insert(subaddr_index); - uint64_t unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD; - std::vector ptx_vector_audit = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, source_asset, m_wallet->get_subaddress({m_current_subaddress_account, subaddr_index}), (subaddr_index>0), 1, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices_single); - ptx_vector.insert(ptx_vector.end(), ptx_vector_audit.begin(), ptx_vector_audit.end()); + + try { + + std::set subaddr_indices_single; + subaddr_indices_single.insert(subaddr_index); + uint64_t unlock_block = get_config(m_wallet->nettype()).AUDIT_LOCK_PERIOD; + std::vector ptx_vector_audit = m_wallet->create_transactions_all(0, cryptonote::transaction_type::AUDIT, source_asset, m_wallet->get_subaddress({m_current_subaddress_account, subaddr_index}), (subaddr_index>0), 1, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices_single); + ptx_vector.insert(ptx_vector.end(), ptx_vector_audit.begin(), ptx_vector_audit.end()); + + } catch (const std::exception &e) { + + // Let's skip this wallet - we have already reported the error + if (unlocked_balance_per_subaddr[subaddr_index].first < 250000000) { + fail_msg_writer() << boost::format(tr("Subaddress index %u has insufficient funds (%s) to pay for audit")) % subaddr_index % print_money(unlocked_balance_per_subaddr[subaddr_index].first); + } + } } } else { diff --git a/src/version.cpp.in b/src/version.cpp.in index bfd9dc5b3..88aa1d6e0 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "0.9.1" +#define DEF_SALVIUM_VERSION "0.9.2" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.3" #define DEF_MONERO_RELEASE_NAME "Zero" From bc7db51f0396334ad7072ffe8e7a6259c0742c03 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Tue, 11 Feb 2025 14:35:57 +0000 Subject: [PATCH 10/11] various fixes ready for next HF --- src/blockchain_utilities/CMakeLists.txt | 78 +++++++++++---------- src/cryptonote_config.h | 2 + src/cryptonote_core/blockchain.cpp | 3 +- src/cryptonote_core/cryptonote_tx_utils.cpp | 1 + src/wallet/api/wallet.cpp | 4 +- 5 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt index ab7130277..5f35d9c9e 100644 --- a/src/blockchain_utilities/CMakeLists.txt +++ b/src/blockchain_utilities/CMakeLists.txt @@ -142,20 +142,23 @@ set(blockchain_scanner_private_headers) monero_private_headers(blockchain_scanner ${blockchain_scanner_private_headers}) -if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp") - set(blockchain_audit_sources - blockchain_audit.cpp - threadpool_boost.cpp - ) - - set(blockchain_audit_private_headers - threadpool_boost.h - ) - - monero_private_headers(blockchain_audit - ${blockchain_audit_private_headers}) +if (BUILD_TAG) else() + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp") + set(blockchain_audit_sources + blockchain_audit.cpp + threadpool_boost.cpp + ) + + set(blockchain_audit_private_headers + threadpool_boost.h + ) + + monero_private_headers(blockchain_audit + ${blockchain_audit_private_headers}) + else() message(STATUS "blockchain_audit.cpp not found - not building the audit tool") + endif() endif() monero_add_executable(blockchain_import @@ -327,33 +330,36 @@ set_property(TARGET blockchain_scanner OUTPUT_NAME "salvium-blockchain-scanner") install(TARGETS blockchain_scanner DESTINATION bin) -if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp") - monero_add_executable(blockchain_audit - ${blockchain_audit_sources} - ${blockchain_audit_private_headers}) +if (BUILD_TAG) +else() + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp") + monero_add_executable(blockchain_audit + ${blockchain_audit_sources} + ${blockchain_audit_private_headers}) - target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc) + target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc) - target_link_libraries(blockchain_audit - PRIVATE - wallet - crypto - cncrypto - cryptonote_core - blockchain_db - version - epee - mysqlcppconn - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${CMAKE_THREAD_LIBS_INIT} - ${EXTRA_LIBRARIES}) + target_link_libraries(blockchain_audit + PRIVATE + wallet + crypto + cncrypto + cryptonote_core + blockchain_db + version + epee + mysqlcppconn + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} + ${EXTRA_LIBRARIES}) - set_property(TARGET blockchain_audit - PROPERTY - OUTPUT_NAME "salvium-blockchain-audit") - install(TARGETS blockchain_audit DESTINATION bin) + set_property(TARGET blockchain_audit + PROPERTY + OUTPUT_NAME "salvium-blockchain-audit") + install(TARGETS blockchain_audit DESTINATION bin) + endif() endif() monero_add_executable(blockchain_stats diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index af48252b9..e57dd38a4 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -231,6 +231,8 @@ #define HF_VERSION_AUDIT1 6 #define HF_VERSION_SALVIUM_ONE_PROOFS 6 +#define HF_VERSION_AUDIT1_PAUSE 7 + #define HF_VERSION_REQUIRE_VIEW_TAGS 255 #define HF_VERSION_ENABLE_CONVERT 255 #define HF_VERSION_ENABLE_ORACLE 255 diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 0ac692224..c68853fe1 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -1505,6 +1505,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl case HF_VERSION_ENFORCE_FULL_PROOFS: case HF_VERSION_SHUTDOWN_USER_TXS: case HF_VERSION_SALVIUM_ONE_PROOFS: + case HF_VERSION_AUDIT1_PAUSE: if (b.miner_tx.amount_burnt > 0) { CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt"); money_in_use += b.miner_tx.amount_burnt; @@ -4087,7 +4088,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, const rct::rctSig &rv = tx.rct_signatures; // Check that after full proofs are enabled, the RCT version is set to enforce full proofs - if (hf_version == HF_VERSION_SALVIUM_ONE_PROOFS) { + if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) { if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) { MERROR_VER("Unsupported rct type (full proofs (with audit data) are required): " << rv.type); return false; diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 6ad024fe5..8e7ba0b58 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -448,6 +448,7 @@ namespace cryptonote case HF_VERSION_ENFORCE_FULL_PROOFS: case HF_VERSION_SHUTDOWN_USER_TXS: case HF_VERSION_SALVIUM_ONE_PROOFS: + case HF_VERSION_AUDIT1_PAUSE: // SRCG: subtract 20% that will be rewarded to staking users CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero"); tx.amount_burnt = amount / 5; diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 8ba862609..ba405de38 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1564,11 +1564,11 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const Monero::transact fake_outs_count = m_wallet->adjust_mixin(mixin_count); if (amount) { - transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, "SAL", "SAL", converted_tx_type, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, asset_type, asset_type, converted_tx_type, fake_outs_count, 0 /* unlock_time */, adjusted_priority, extra, subaddr_account, subaddr_indices); } else { - transaction->m_pending_tx = m_wallet->create_transactions_all(0, converted_tx_type, "SAL", info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_all(0, converted_tx_type, asset_type, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, adjusted_priority, extra, subaddr_account, subaddr_indices); } From aa64124c287f5d15a8cb9766128a67bb2e54d5b4 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Fri, 14 Feb 2025 13:28:22 +0000 Subject: [PATCH 11/11] fix for supply_info command with SAL supply going negative --- README.md | 10 +++++----- src/blockchain_db/lmdb/db_lmdb.cpp | 5 +++++ src/version.cpp.in | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5f08cfc2b..9b5137d1e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salvium Zero v0.9.2 +# Salvium Zero v0.9.3 Copyright (c) 2023-2024, Salvium Portions Copyright (c) 2014-2023, The Monero Project @@ -172,7 +172,7 @@ invokes cmake commands as needed. ```bash cd salvium - git checkout v0.9.2 + git checkout v0.9.3 make ``` @@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch ( ```bash git clone https://github.com/salvium/salvium cd salvium - git checkout v0.9.2 + git checkout v0.9.3 ``` * Build: @@ -370,10 +370,10 @@ application. cd salvium ``` -* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.2'. If you don't care about the version and just want binaries from master, skip this step: +* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.3'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.9.2 + git checkout v0.9.3 ``` * If you are on a 64-bit system, run: diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 935bfb1e2..f9b5d3b80 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -3778,6 +3778,11 @@ std::map BlockchainLMDB::get_circulating_supply() const //amount += m_coinbase; } + if (amount < 0) { + // Negative number can't be converted to a 64-bit UINT, so return 0, but retain -ve number privately + LOG_PRINT_L2("BlockchainLMDB::" << __func__ << " - supply of " << currency_label << " is negative (" << amount << ") but outputting zero"); + amount = 0; + } circulating_supply[currency_label] = amount.convert_to(); } diff --git a/src/version.cpp.in b/src/version.cpp.in index 88aa1d6e0..d28dc6af4 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@" -#define DEF_SALVIUM_VERSION "0.9.2" +#define DEF_SALVIUM_VERSION "0.9.3" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.3" #define DEF_MONERO_RELEASE_NAME "Zero"