From b713a08a81c40b21e45303d22013ae9d48c60b82 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Tue, 25 Feb 2025 13:04:29 +0000 Subject: [PATCH] bumped version, ready for fork; fixed up wallet API method for auditing --- README.md | 10 +- src/blocks/checkpoints.dat | Bin 14980 -> 21188 bytes src/cryptonote_core/blockchain.cpp | 154 +++++++++------------- src/cryptonote_core/cryptonote_tx_utils.h | 1 + src/version.cpp.in | 2 +- src/wallet/api/wallet.cpp | 47 ++++--- src/wallet/wallet2.cpp | 5 +- 7 files changed, 104 insertions(+), 115 deletions(-) diff --git a/README.md b/README.md index 1b42c67ce..9d9f38947 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salvium Zero v0.9.4 +# Salvium Zero v0.9.5 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.4 + git checkout v0.9.5 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.4 + git checkout v0.9.5 ``` * 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.4'. 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.5'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.9.4 + git checkout v0.9.5 ``` * If you are on a 64-bit system, run: diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat index 8ba5bc6e79341a097ef26b26e51badc223c35f8c..8455b1dabedb6eb5644a0d72de4f9e0785cef6d4 100644 GIT binary patch delta 6269 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 audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS; - uint64_t audit_lock_period = get_config(m_nettype).AUDIT_LOCK_PERIOD; - uint64_t matured_audit_height = height - audit_lock_period - 1; - uint8_t hf = m_hardfork->get_ideal_version(matured_audit_height); - if (audit_hard_forks.find(hf) != audit_hard_forks.end()) { - // Maturing height was during an audit - process accordingly - cryptonote::audit_block_info abi_matured; - ok = get_abi_entry(matured_audit_height, abi_matured); - if (!ok) { - LOG_PRINT_L1("Block at height: " << height << " - failed to obtain audit block information - aborting"); - return false; - } else if (abi_matured.locked_coins_this_block == 0) { - LOG_PRINT_L1("Block at height: " << height << " - no audit payouts due - skipping"); - } else { - // Iterate over the cached data for audits, calculating the audit payouts due - if (!calculate_audit_payouts(matured_audit_height, audit_payouts)) { - LOG_ERROR("Block at height: " << height << " - Failed to obtain audit payout information - aborting"); - return false; - } - } - } - */ + // Check we have the correct number of entries CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size() + audit_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; - uint64_t out_unlock_time; - std::string out_asset_type; + //std::set used_keys; + + // Merge the yield and audit payouts into an iterable vector + std::vector> payouts{yield_payouts}; + payouts.insert(payouts.end(), audit_payouts.begin(), audit_payouts.end()); + /* + if (hf_version >= HF_VERSION_AUDIT2) { + std::sort(payouts.begin(), payouts.end(), [](const auto& lhs, const auto& rhs) { + // If block heights are different (only possible with mixed AUDIT+STAKE) sort by them first + if (lhs.first.block_height < rhs.first.block_height) return true; + if (lhs.first.block_height > rhs.first.block_height) return false; + + // If output keys are different, sort by them second + if (lhs.first.return_address < rhs.first.return_address) return true; + if (lhs.first.return_address > rhs.first.return_address) return false; + + // If block heights _and_ output keys are same, sort by amount third + return lhs.second < rhs.second; + }); + } + */ + + size_t output_idx = 0; + for (auto it = payouts.begin(); it != payouts.end(); it++, output_idx++) { + + // Verify the output key crypto::public_key out_key; - if (o.target.type() == typeid(txout_to_key)) { - txout_to_key out = boost::get(o.target); - 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); - 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; - } + cryptonote::get_output_public_key(b.protocol_tx.vout[output_idx], out_key); + CHECK_AND_ASSERT_MES(out_key == it->first.return_address, false, "Incorrect output key detected in protocol_tx"); - // 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 or audit payouts for this output - std::string expected_output_asset_type = "SAL"; - auto found_yield = std::find_if(yield_payouts.begin(), yield_payouts.end(), [&](const std::pair& p) { - return p.first.return_address == out_key; - }); - auto found_audit = std::find_if(audit_payouts.begin(), audit_payouts.end(), [&](const std::pair& p) { - return p.first.return_address == out_key; - }); - if (found_yield == yield_payouts.end() && found_audit == audit_payouts.end()) { - MERROR("Block at height: " << height << " - Failed to locate output for protocol TX - rejecting block"); - return false; - } else if (found_audit == audit_payouts.end()) { + // Verify the output amount + CHECK_AND_ASSERT_MES(b.protocol_tx.vout[output_idx].amount == it->second, false, "Incorrect output amount detected in protocol_tx"); - // Found a YIELD entry - CHECK_AND_ASSERT_MES(out_amount == found_yield->second, false, "Incorrect value for protocol TX YIELD amount"); - uint8_t hf_yield = m_hardfork->get_ideal_version(found_yield->first.block_height); - if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS) - expected_output_asset_type = "SAL1"; + // Verify the output asset type + std::string out_asset_type; + cryptonote::get_output_asset_type(b.protocol_tx.vout[output_idx], out_asset_type); + uint8_t hf_yield = m_hardfork->get_ideal_version(it->first.block_height); + if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS) + CHECK_AND_ASSERT_MES(out_asset_type == "SAL1", false, "Incorrect output asset_type (!= SAL1) detected in protocol_tx"); + else + CHECK_AND_ASSERT_MES(out_asset_type == "SAL", false, "Incorrect output asset_type (!= SAL) detected in protocol_tx"); - } else if (found_yield == yield_payouts.end()) { - - // Found an AUDIT entry - CHECK_AND_ASSERT_MES(out_amount == found_audit->second, false, "Incorrect value for protocol TX AUDIT amount"); - uint8_t hf_audit = m_hardfork->get_ideal_version(found_audit->first.block_height); - if (hf_audit >= HF_VERSION_SALVIUM_ONE_PROOFS) - expected_output_asset_type = "SAL1"; - - } else { - - // Duplicate entry in yield + audit?!?!? - MERROR("Block at height: " << height << " - Duplicated YIELD and AUDIT keys found for protocol TX - 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(expected_output_asset_type == out_asset_type, false, "Incorrect asset type detected for protocol TX ouput - rejecting block"); + // Verify the output unlock time + uint64_t out_unlock_time; + cryptonote::get_output_unlock_time(b.protocol_tx.vout[output_idx], out_unlock_time); + CHECK_AND_ASSERT_MES(out_unlock_time == CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "Invalid output unlock time on protocol_tx output"); } // Everything checks out @@ -2003,6 +1957,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, entry.type = cryptonote::transaction_type::STAKE; entry.P_change = yield_entry.first.P_change; entry.return_pubkey = yield_entry.first.return_pubkey; + entry.origin_height = start_height; protocol_entries.push_back(entry); } } @@ -2046,12 +2001,31 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block, entry.type = cryptonote::transaction_type::AUDIT; entry.P_change = audit_entry.first.P_change; entry.return_pubkey = audit_entry.first.return_pubkey; + entry.origin_height = matured_audit_height; protocol_entries.push_back(entry); } } break; } } + + /* + // From v8, we sort the protocol_tx outputs by ORIGIN_HEIGHT, OUTPUT_KEY, AMOUNT + if (b.major_version >= HF_VERSION_AUDIT2) { + std::sort(protocol_entries.begin(), protocol_entries.end(), [](const auto& lhs, const auto& rhs) { + // If origin block heights are different (only possible with mixed AUDIT+STAKE) sort by them first + if (lhs.origin_height < rhs.origin_height) return true; + if (lhs.origin_height > rhs.origin_height) return false; + + // If output keys are different, sort by them second + if (lhs.return_address < rhs.return_address) return true; + if (lhs.return_address > rhs.return_address) return false; + + // If block heights _and_ output keys are same, sort by amount third + return lhs.amount_burnt < rhs.amount_burnt; + }); + } + */ // Time to construct the protocol_tx uint64_t protocol_fee = 0; @@ -6309,7 +6283,7 @@ void Blockchain::cancel() } #if defined(PER_BLOCK_CHECKPOINT) -static const char expected_block_hashes_hash[] = "5065d5361119a526b7a45e9e5bdf1d5be86f80e9eb43b0398bf0e47489c81c6d"; +static const char expected_block_hashes_hash[] = "131b18108fb3382b4fa82d4eb6cca8f9e1e0ee2aa7893e572361ca0c2c4118e6"; void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints) { if (get_checkpoints == nullptr || !m_fast_sync) diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 4fbb9956d..02f162c31 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -66,6 +66,7 @@ namespace cryptonote uint8_t type; crypto::public_key P_change; crypto::public_key return_pubkey; + uint64_t origin_height; }; //--------------------------------------------------------------- diff --git a/src/version.cpp.in b/src/version.cpp.in index 4f481c494..35d942a24 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.4" +#define DEF_SALVIUM_VERSION "0.9.5" #define DEF_MONERO_VERSION_TAG "release" #define DEF_MONERO_VERSION "0.18.3.3" #define DEF_MONERO_RELEASE_NAME "Zero" diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 174c91978..662658de3 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -1569,27 +1569,38 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const Monero::transact extra, subaddr_account, subaddr_indices); } else { std::vector m_pending_txs; - for (auto it = subaddr_indices.begin(); it != subaddr_indices.end(); ++it) { + for (const auto subaddr_index : subaddr_indices) { // Skip this wallet if there is no balance unlocked to audit - const auto unlocked_balance_per_subaddr = m_wallet->unlocked_balance_per_subaddress(subaddr_account, "SAL", true); - if (unlocked_balance_per_subaddr.count(*it) == 0) continue; + std::map>> unlocked_balance_per_subaddr = m_wallet->unlocked_balance_per_subaddress(subaddr_account, asset_type, true); + if (unlocked_balance_per_subaddr.count(subaddr_index) == 0) continue; - const auto result = m_wallet->create_transactions_all( - 0, - converted_tx_type, - asset_type, - m_wallet->get_subaddress({subaddr_account, *it}), - ((*it) > 0), - 1, - fake_outs_count, - 0 /* unlock_time */, - adjusted_priority, - extra, - subaddr_account, - std::set {*it} - ); - m_pending_txs.insert(m_pending_txs.end(), result.begin(), result.end()); + try { + + const auto result = m_wallet->create_transactions_all(0, + converted_tx_type, + asset_type, + m_wallet->get_subaddress({subaddr_account, subaddr_index}), + (subaddr_index > 0), + 1, + fake_outs_count, + 0 /* unlock_time */, + adjusted_priority, + extra, + subaddr_account, + std::set {subaddr_index} + ); + m_pending_txs.insert(m_pending_txs.end(), result.begin(), result.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) { + std::ostringstream writer; + 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); + setStatusError(writer.str()); + } + } } transaction->m_pending_tx = m_pending_txs; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index c1566d001..f3f824e01 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2768,7 +2768,10 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote crypto::public_key pk_locked_coins = crypto::null_pkey; THROW_WALLET_EXCEPTION_IF(!get_output_public_key(td_origin.m_tx.vout[td_origin.m_internal_output_index], pk_locked_coins), error::wallet_internal_error, "Failed to get output public key for locked coins"); // At this point, we need to clear the "locked coins" count, because otherwise we will be counting yield stakes twice in our balance - THROW_WALLET_EXCEPTION_IF(!m_locked_coins.erase(pk_locked_coins), error::wallet_internal_error, "Failed to remove protocol_tx entry from m_locked_coins"); + //THROW_WALLET_EXCEPTION_IF(!m_locked_coins.erase(pk_locked_coins), error::wallet_internal_error, "Failed to remove protocol_tx entry from m_locked_coins"); + if (!m_locked_coins.erase(pk_locked_coins)) { + LOG_ERROR("Failed to remove protocol_tx entry from m_locked_coins - possible duplicate output key detected"); + } } } }