From d3f15211d7e36a30ea6d999a117cd5a54aa9be78 Mon Sep 17 00:00:00 2001 From: Some Random Crypto Guy Date: Thu, 3 Oct 2024 10:01:29 +0100 Subject: [PATCH] updated to support multisig wallets; fixed a couple of minor bugs; removed some extraneous code; bumped version --- README.md | 8 +- src/cryptonote_core/cryptonote_tx_utils.cpp | 20 ----- src/cryptonote_core/cryptonote_tx_utils.h | 1 + src/multisig/multisig_tx_builder_ringct.cpp | 86 ++++++++++++++------- src/ringct/rctSigs.cpp | 5 +- src/ringct/rctSigs.h | 2 - src/version.cpp.in | 2 +- src/wallet/wallet2.cpp | 42 +--------- src/wallet/wallet2.h | 1 - 9 files changed, 65 insertions(+), 102 deletions(-) diff --git a/README.md b/README.md index e574ff5..a15b11a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Salvium Zero v0.4.1 +# Salvium Zero v0.5.3 Copyright (c) 2023-2024, Salvium Portions Copyright (c) 2014-2023, The Monero Project @@ -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.4.1 + git checkout v0.5.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.4.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.5.3'. If you don't care about the version and just want binaries from master, skip this step: ```bash - git checkout v0.4.1 + git checkout v0.5.3 ``` * If you are on a 64-bit system, run: diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index dc9250b..a1c2331 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -1102,26 +1102,7 @@ namespace cryptonote if (sources[i].rct) boost::get(tx.vin[i]).amount = 0; } - std::vector zero_masks; - zero_masks.reserve(tx.vout.size()); for (size_t i = 0; i < tx.vout.size(); ++i) { - if (tx.type == cryptonote::transaction_type::STAKE) { - uint64_t unlock_time = 0; - bool ok = get_output_unlock_time(tx.vout[i], unlock_time); - if (!ok) { - LOG_ERROR("failed to get output asset type for tx.vout[" << i << "]"); - return false; - } - if (unlock_time == 0) { - zero_masks.emplace_back(false); - } else { - zero_masks.emplace_back(true); - } - } else { - zero_masks.emplace_back(false); - } - - // Clear the amount in the output tx.vout[i].amount = 0; } @@ -1136,7 +1117,6 @@ namespace cryptonote tx_type, source_asset, destination_asset_types, - zero_masks, inamounts, outamounts, fee, diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index a342627..f7bf7da 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -150,6 +150,7 @@ namespace cryptonote FIELD(original) VARINT_FIELD(amount) FIELD(addr) + FIELD(asset_type) FIELD(is_subaddress) FIELD(is_integrated) FIELD(is_change) diff --git a/src/multisig/multisig_tx_builder_ringct.cpp b/src/multisig/multisig_tx_builder_ringct.cpp index 1d4cfd9..c0d62f7 100644 --- a/src/multisig/multisig_tx_builder_ringct.cpp +++ b/src/multisig/multisig_tx_builder_ringct.cpp @@ -404,7 +404,10 @@ static bool compute_keys_for_destinations( rct::keyV& output_amount_secret_keys, std::vector& asset_types, std::vector& view_tags, + std::vector& destination_amounts, const cryptonote::transaction_type& tx_type, + bool& found_change, + std::size_t& change_index, cryptonote::transaction& unsigned_tx ) { @@ -485,29 +488,35 @@ static bool compute_keys_for_destinations( } // additional tx pubkeys: R_t - output_public_keys.resize(num_destinations); - view_tags.resize(num_destinations); + output_public_keys.clear(); + view_tags.clear(); + asset_types.clear(); + destination_amounts.clear(); + found_change = false; std::vector tx_aux_public_keys; crypto::public_key temp_output_public_key; - + size_t output_index = 0; + uint64_t amount_burnt = 0; + uint64_t amount_slippage_limit = 0; for (std::size_t i = 0; i < num_destinations; ++i) { // Is this a BURN or CONVERT TX? if (tx_type == cryptonote::transaction_type::BURN || tx_type == cryptonote::transaction_type::CONVERT) { // Do not create outputs that are for the destination asset type - discard them as unused if (destinations[i].asset_type == unsigned_tx.destination_asset_type) { - unsigned_tx.amount_burnt += destinations[i].amount; - unsigned_tx.amount_slippage_limit = destinations[i].slippage_limit; + amount_burnt += destinations[i].amount; + amount_slippage_limit = destinations[i].slippage_limit; continue; } } else if (tx_type == cryptonote::transaction_type::STAKE) { // Do not create outputs that are staked for yield - discard them as unused if (!destinations[i].is_change) { - unsigned_tx.amount_burnt += destinations[i].amount; + amount_burnt += destinations[i].amount; continue; } } + crypto::view_tag vt; // Temporary variable to hold the view tag in case we create one if (not hwdev.generate_output_ephemeral_keys( unsigned_tx.version, account_keys, @@ -515,23 +524,42 @@ static bool compute_keys_for_destinations( tx_secret_key, destinations[i], change.addr, - i, + output_index, need_tx_aux_keys, tx_aux_secret_keys, tx_aux_public_keys, output_amount_secret_keys, temp_output_public_key, use_view_tags, - view_tags[i] //unused variable if use_view_tags is not set + vt )) { return false; } - output_public_keys[i] = rct::pk2rct(temp_output_public_key); + output_public_keys.push_back(rct::pk2rct(temp_output_public_key)); + asset_types.push_back(destinations[i].asset_type); + if (use_view_tags) + view_tags.push_back(vt); + destination_amounts.push_back(destinations[i].amount); + if (destinations[i].is_change) { + found_change = true; + change_index = output_index; // Store the change_index - we will need this + } + output_index++; } - if (num_destinations != output_amount_secret_keys.size()) - return false; + //if (num_destinations != output_amount_secret_keys.size()) + // return false; + if (reconstruction) { + // Verify the values match the unsigned_tx + CHECK_AND_ASSERT_MES(amount_burnt == unsigned_tx.amount_burnt, false, "Internal error - amount_burnt does not match unsigned_tx"); + CHECK_AND_ASSERT_MES(amount_slippage_limit == unsigned_tx.amount_slippage_limit, false, "Internal error - amount_slippage_limit does not match unsigned_tx"); + } else { + // Store the calculated values + unsigned_tx.amount_burnt = amount_burnt; + unsigned_tx.amount_slippage_limit = amount_slippage_limit; + } + CHECK_AND_ASSERT_MES( tx_aux_public_keys.size() == tx_aux_secret_keys.size(), false, @@ -691,6 +719,7 @@ static bool set_tx_return_address_information(const cryptonote::account_keys& ac CHECK_AND_ASSERT_MES(unsigned_tx.vout.size() == 2, false, "Internal error - incorrect number of outputs (!=2) for TRANSFER tx"); else if (unsigned_tx.type == cryptonote::transaction_type::STAKE) CHECK_AND_ASSERT_MES(unsigned_tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for YIELD tx"); + CHECK_AND_ASSERT_MES(change_index < unsigned_tx.vout.size(), false, "Internal error - invalid change_index"); CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(unsigned_tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key"); CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx"); @@ -770,7 +799,7 @@ static bool set_tx_return_address_information(const cryptonote::account_keys& ac static bool set_tx_rct_signatures( const std::uint64_t fee, const std::vector& sources, - const std::vector& destinations, + const std::vector& destination_amounts, const rct::keyV& input_secret_keys, const rct::keyV& output_public_keys, const rct::keyV& output_amount_secret_keys, @@ -787,7 +816,7 @@ static bool set_tx_rct_signatures( if (rct_config.range_proof_type != rct::RangeProofPaddedBulletproof) return false; - const std::size_t num_destinations = destinations.size(); + const std::size_t num_destinations = destination_amounts.size(); const std::size_t num_sources = sources.size(); // rct_signatures component of tx @@ -810,7 +839,7 @@ static bool set_tx_rct_signatures( rv.outPk.resize(num_destinations); for (std::size_t i = 0; i < num_destinations; ++i) { rv.outPk[i].dest = output_public_keys[i]; - output_amounts[i] = destinations[i].amount; + output_amounts[i] = destination_amounts[i]; output_amount_masks[i] = genCommitmentMask(output_amount_secret_keys[i]); rv.ecdhInfo[i].amount = rct::d2h(output_amounts[i]); rct::addKeys2( @@ -883,7 +912,9 @@ static bool set_tx_rct_signatures( if (num_sources != rv.p.pseudoOuts.size()) return false; rct::key balance_accumulator = rct::scalarmultH(rct::d2h(fee)); + rct::key txnAmountBurntKey = rct::scalarmultH(rct::d2h(unsigned_tx.amount_burnt)); rct::addKeys(balance_accumulator, balance_accumulator, rv.p_r); + rct::addKeys(balance_accumulator, balance_accumulator, txnAmountBurntKey); for (const auto& e: rv.outPk) rct::addKeys(balance_accumulator, balance_accumulator, e.mask); for (const auto& pseudoOut: rv.p.pseudoOuts) @@ -1086,6 +1117,9 @@ bool tx_builder_ringct_t::init( rct::keyV output_amount_secret_keys; std::vector asset_types; std::vector view_tags; + std::vector destination_amounts; + bool found_change{false}; + std::size_t change_index; auto output_amount_secret_keys_wiper = epee::misc_utils::create_scope_leave_handler([&]{ memwipe(static_cast(output_amount_secret_keys.data()), output_amount_secret_keys.size() * sizeof(rct::key)); }); @@ -1103,10 +1137,17 @@ bool tx_builder_ringct_t::init( output_amount_secret_keys, asset_types, view_tags, + destination_amounts, tx_type, + found_change, + change_index, unsigned_tx)) return false; + // Check that the change element was found + if (!found_change) + return false; + // add inputs to tx set_tx_inputs(sources, unsigned_tx); @@ -1122,29 +1163,16 @@ bool tx_builder_ringct_t::init( if (unsigned_tx.type == cryptonote::transaction_type::TRANSFER || unsigned_tx.type == cryptonote::transaction_type::STAKE) { - // Identify the change output - bool found_change{false}; - size_t change_idx{0}; - for (size_t idx=0; idx & destination_asset_types, - const std::vector &zero_masks, const std::vector &inamounts, const std::vector &outamounts, xmr_amount txnFee, @@ -1127,7 +1126,6 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(inamounts.size() == inSk.size(), "Different number of inamounts/inSk"); CHECK_AND_ASSERT_THROW_MES(outamounts.size() == destinations.size(), "Different number of amounts/destinations"); CHECK_AND_ASSERT_THROW_MES(amount_keys.size() == destinations.size(), "Different number of amount_keys/destinations"); - CHECK_AND_ASSERT_THROW_MES(zero_masks.size() == destinations.size(), "Different number of zero_masks/destinations"); CHECK_AND_ASSERT_THROW_MES(index.size() == inSk.size(), "Different number of index/inSk"); CHECK_AND_ASSERT_THROW_MES(mixRing.size() == inSk.size(), "Different number of mixRing/inSk"); for (size_t n = 0; n < mixRing.size(); ++n) { @@ -1312,7 +1310,6 @@ namespace rct { const cryptonote::transaction_type tx_type, const std::string& in_asset_type, const std::vector & destination_asset_types, - const std::vector &zero_masks, const std::vector &inamounts, const std::vector &outamounts, const keyV &amount_keys, @@ -1330,7 +1327,7 @@ namespace rct { mixRing[i].resize(mixin+1); index[i] = populateFromBlockchainSimple(mixRing[i], inPk[i], mixin); } - return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, zero_masks, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev); + return genRctSimple(message, inSk, destinations, tx_type, in_asset_type, destination_asset_types, inamounts, outamounts, txnFee, mixRing, amount_keys, index, outSk, rct_config, hwdev); } //RingCT protocol diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index d0b4482..020394f 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -136,7 +136,6 @@ namespace rct { const cryptonote::transaction_type tx_type, const std::string& in_asset_type, const std::vector & destination_asset_types, - const std::vector &zero_masks, const std::vector & inamounts, const std::vector & outamounts, const keyV &amount_keys, @@ -152,7 +151,6 @@ namespace rct { const cryptonote::transaction_type tx_type, const std::string& in_asset_type, const std::vector & destination_asset_types, - const std::vector &zero_masks, const std::vector & inamounts, const std::vector & outamounts, xmr_amount txnFee, diff --git a/src/version.cpp.in b/src/version.cpp.in index 6dcddb9..c3827e6 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.5.2" +#define DEF_SALVIUM_VERSION "0.5.3" #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/wallet2.cpp b/src/wallet/wallet2.cpp index cd5cb2e..e9c3df0 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2470,51 +2470,11 @@ bool wallet2::get_yield_summary_info(uint64_t &total_burnt, yield_per_stake_128 /= ybi_data.back().locked_coins_tally; yield_per_stake = yield_per_stake_128.convert_to(); } - /* - // Iterate over the transfers in our wallet - std::map map_payouts; - for (size_t idx = m_transfers.size()-1; idx>0; --idx) { - const tools::wallet2::transfer_details& td = m_transfers[idx]; - //if (td.m_block_height < ybi_data[0].block_height) break; - if (td.m_tx.type == cryptonote::transaction_type::STAKE) { - if (map_payouts.count(idx)) { - payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt)); - } else { - payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, 0)); - } - } else if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) { - // Store list of reverse-lookup indices to tell YIELD TXs how much they earned - if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE) - map_payouts[td.m_td_origin_idx] = idx; - } - } - */ + // Return success to caller return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_yield_payouts(std::vector> &payouts) { - - // Iterate over the transfers in our wallet - std::map map_payouts; - for (size_t idx = m_transfers.size()-1; idx>0; --idx) { - const tools::wallet2::transfer_details& td = m_transfers[idx]; - //if (td.m_block_height < ybi_data[0].block_height) break; - if (td.m_tx.type == cryptonote::transaction_type::STAKE) { - if (map_payouts.count(idx)) { - payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, m_transfers[map_payouts[idx]].m_amount - td.m_tx.amount_burnt)); - } else { - payouts.push_back(std::make_tuple(td.m_block_height, epee::string_tools::pod_to_hex(td.m_txid), td.m_tx.amount_burnt, 0)); - } - } else if (td.m_tx.type == cryptonote::transaction_type::PROTOCOL) { - // Store list of reverse-lookup indices to tell YIELD TXs how much they earned - if (m_transfers[td.m_td_origin_idx].m_tx.type == cryptonote::transaction_type::STAKE) - map_payouts[td.m_td_origin_idx] = idx; - } - } - return true; -} -//---------------------------------------------------------------------------------------------------- void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector &o_indices, const std::vector &asset_type_output_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map, size_t> *output_tracker_cache, bool ignore_callbacks) { PERF_TIMER(process_new_transaction); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index dee821c..ee90e53 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1755,7 +1755,6 @@ private: uint64_t &ybi_data_size, std::vector> &payouts ); - bool get_yield_payouts(std::vector> &payouts); private: /*!