diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index ae200221e..b2e054b5a 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -127,7 +127,7 @@ struct output_data_t crypto::public_key pubkey; //!< the output's public key (for spend verification) uint64_t unlock_time; //!< the output's unlock time (or height) uint64_t height; //!< the height of the block which created the output - char asset_type[8]; //!< the asset type of the output + uint32_t asset_type; //!< the asset type of the output rct::key commitment; //!< the output's amount commitment (for spend verification) }; #pragma pack(pop) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 56c512578..e368ddcb5 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -71,7 +71,7 @@ struct pre_rct_output_data_t crypto::public_key pubkey; //!< the output's public key (for spend verification) uint64_t unlock_time; //!< the output's unlock time (or height) uint64_t height; //!< the height of the block which created the output - char asset_type[8]; //!< the asset type of the output + uint32_t asset_type; //!< the asset type of the output }; #pragma pack(pop) @@ -1075,19 +1075,6 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons if (tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::BURN) { - /* - // Conversion TX - update our records - circ_supply cs; - cs.tx_hash = tx_hash; - cs.asset_type = cryptonote::asset_id_from_type(tx.source_asset_type); - cs.amount_burnt = tx.amount_burnt; - cs.amount_minted = 0; - - MDB_val_set(val_circ_supply, cs); - result = mdb_cursor_put(m_cur_circ_supply, &val_tx_id, &val_circ_supply, MDB_APPEND); - if (result) - throw0(DB_ERROR( lmdb_error("Failed to add tx circulating supply to db transaction: ", result).c_str() )); - */ // Get the current tally value for the source currency type MDB_val_copy source_idx(cryptonote::asset_id_from_type(tx.source_asset_type)); boost::multiprecision::int128_t source_tally = 0; @@ -1116,20 +1103,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons bool ok = cryptonote::get_output_asset_type(out, asset_type); if (!ok) throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)")); - /* - circ_supply cs; - cs.tx_hash = tx_hash; - cs.asset_type = cryptonote::asset_id_from_type(asset_type); - cs.amount_burnt = 0; - cs.amount_minted = out.amount; - */ minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount; - /* - MDB_val_set(val_circ_supply, cs); - result = mdb_cursor_put(m_cur_circ_supply, &val_tx_id, &val_circ_supply, MDB_APPENDDUP); - if (result) - throw0(DB_ERROR( lmdb_error("Failed to add tx circulating supply to db transaction: ", result).c_str() )); - */ } // Now update the overall tally entries @@ -1360,6 +1334,8 @@ std::pair BlockchainLMDB::add_output(const crypto::hash& tx_ if (result) throw0(DB_ERROR(lmdb_error("Failed to add output tx hash to db transaction: ", result).c_str())); + uint32_t asset_type = cryptonote::asset_id_from_type(output_asset_type); + outkey ok; MDB_val data; MDB_val_copy val_amount(tx_output.amount); @@ -1380,11 +1356,7 @@ std::pair BlockchainLMDB::add_output(const crypto::hash& tx_ ok.data.pubkey = output_public_key; ok.data.unlock_time = unlock_time; ok.data.height = m_height; - - if(output_asset_type.length() >= sizeof(ok.data.asset_type)) - throw0(DB_ERROR(lmdb_error("Invalid asset_type " + output_asset_type, result).c_str())); - memset(ok.data.asset_type, 0, sizeof(ok.data.asset_type)); - memcpy(ok.data.asset_type, output_asset_type.c_str(), output_asset_type.length()); + ok.data.asset_type = asset_type; if (tx_output.amount == 0) { @@ -1401,7 +1373,7 @@ std::pair BlockchainLMDB::add_output(const crypto::hash& tx_ throw0(DB_ERROR(lmdb_error("Failed to add output pubkey to db transaction: ", result).c_str())); - MDB_val_copy k(output_asset_type.c_str()); + MDB_val_copy k(asset_type); MDB_val v; mdb_size_t num_outputs_of_asset_type = 0; @@ -1420,7 +1392,7 @@ std::pair BlockchainLMDB::add_output(const crypto::hash& tx_ oat.output_id = ok.output_id; MDB_val_set(voat, oat); - MDB_val_copy koat(output_asset_type.c_str()); + MDB_val_copy koat(asset_type); if ((result = mdb_cursor_put(m_cur_output_types, &koat, &voat, MDB_APPENDDUP))) throw0(DB_ERROR(lmdb_error("Failed to add output type to db transaction: ", result).c_str())); @@ -1469,14 +1441,14 @@ void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_id, const transaction& for (size_t i = tx.vout.size(); i-- > 0;) { uint64_t amount = is_pseudo_rct ? 0 : tx.vout[i].amount; - std::string output_asset_type; - if (!get_output_asset_type(tx.vout[i], output_asset_type)) + std::string output_asset_type_str; + if (!get_output_asset_type(tx.vout[i], output_asset_type_str)) throw0(DB_ERROR("Could not get an output asset_type from a tx output (removing).")); - remove_output(amount, amount_output_indices[i].first, output_asset_type, amount_output_indices[i].second); + remove_output(amount, amount_output_indices[i].first, output_asset_type_str, amount_output_indices[i].second); } } -void BlockchainLMDB::remove_output(const uint64_t amount, const uint64_t& out_index, const std::string& output_asset_type, const uint64_t& asset_type_output_id) +void BlockchainLMDB::remove_output(const uint64_t amount, const uint64_t& out_index, const std::string& output_asset_type_str, const uint64_t& asset_type_output_id) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -1506,8 +1478,8 @@ void BlockchainLMDB::remove_output(const uint64_t amount, const uint64_t& out_in throw1(DB_ERROR(lmdb_error("Error adding removal of output tx to db transaction", result).c_str())); } - - MDB_val_copy koat(output_asset_type.c_str()); + uint32_t output_asset_type = cryptonote::asset_id_from_type(output_asset_type_str); + MDB_val_copy koat(output_asset_type); MDB_val_set(voat, asset_type_output_id); result = mdb_cursor_get(m_cur_output_types, &koat, &voat, MDB_GET_BOTH); @@ -2913,7 +2885,10 @@ std::pair, uint64_t> BlockchainLMDB::get_block_cumulative_ } const mdb_block_info *bi = ((const mdb_block_info *)v.mv_data) + (height - range_begin); - res.push_back(bi->bi_cum_rct_by_asset_type[asset_type]); + // if no asset type is provided in the request, an old client is requesting the cumulative outputs, + // and is expecting the global output distribution that isn't bucketed by asset type in response + res.push_back(asset_type.empty() ? bi->bi_cum_rct : bi->bi_cum_rct_by_asset_type[asset_type]); + if (height == heights[heights.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE]) num_spendable_global_outs = bi->bi_cum_rct; @@ -3822,7 +3797,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const return num_elems; } -uint64_t BlockchainLMDB::get_num_outputs_of_asset_type(const std::string asset_type) const +uint64_t BlockchainLMDB::get_num_outputs_of_asset_type(const std::string asset_type_str) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -3830,7 +3805,8 @@ uint64_t BlockchainLMDB::get_num_outputs_of_asset_type(const std::string asset_t TXN_PREFIX_RDONLY(); RCURSOR(output_types); - MDB_val_copy k(asset_type.c_str()); + uint32_t asset_type = cryptonote::asset_id_from_type(asset_type_str); + MDB_val_copy k(asset_type); MDB_val v; mdb_size_t num_outputs_of_asset_type = 0; auto result = mdb_cursor_get(m_cur_output_types, &k, &v, MDB_SET); @@ -3882,7 +3858,7 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6 return ret; } -void BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::string asset_type, const std::vector &asset_type_output_indices, std::vector &output_indices) const +void BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::string asset_type_str, const std::vector &asset_type_output_indices, std::vector &output_indices) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -3893,7 +3869,8 @@ void BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::strin RCURSOR(output_types); - MDB_val_copy k_type(asset_type.c_str()); + uint32_t asset_type = cryptonote::asset_id_from_type(asset_type_str); + MDB_val_copy k_type(asset_type); for (size_t i = 0; i < asset_type_output_indices.size(); ++i) { @@ -3902,7 +3879,7 @@ void BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::strin auto get_result = mdb_cursor_get(m_cur_output_types, &k_type, &v, MDB_GET_BOTH); if (get_result == MDB_NOTFOUND) { - throw1(OUTPUT_DNE((std::string("Attempting to get output id by asset type output id (asset type " + asset_type + " asset type ouput id " + boost::lexical_cast(asset_type_output_indices[i]) + "), but key does not exist (current height " + boost::lexical_cast(height()) + ")").c_str()))); + throw1(OUTPUT_DNE((std::string("Attempting to get output id by asset type output id (asset type " + asset_type_str + " asset type ouput id " + boost::lexical_cast(asset_type_output_indices[i]) + "), but key does not exist (current height " + boost::lexical_cast(height()) + ")").c_str()))); } else if (get_result) throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output id by asset type output id from the db", get_result).c_str())); @@ -3914,7 +3891,7 @@ void BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::strin TXN_POSTFIX_RDONLY(); } -uint64_t BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::string asset_type, const uint64_t &asset_type_output_index) const +uint64_t BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::string asset_type_str, const uint64_t &asset_type_output_index) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -3922,13 +3899,14 @@ uint64_t BlockchainLMDB::get_output_id_from_asset_type_output_index(const std::s TXN_PREFIX_RDONLY(); RCURSOR(output_types); - MDB_val_copy k_type(asset_type.c_str()); + uint32_t asset_type = cryptonote::asset_id_from_type(asset_type_str); + MDB_val_copy k_type(asset_type); MDB_val_set(v, asset_type_output_index); auto get_result = mdb_cursor_get(m_cur_output_types, &k_type, &v, MDB_GET_BOTH); if (get_result == MDB_NOTFOUND) { - throw1(OUTPUT_DNE((std::string("Attempting to get output id by asset type output id (asset type " + asset_type + " asset type output id " + boost::lexical_cast(asset_type_output_index) + "), but key does not exist (current height " + boost::lexical_cast(height()) + ")").c_str()))); + throw1(OUTPUT_DNE((std::string("Attempting to get output id by asset type output id (asset type " + asset_type_str + " asset type output id " + boost::lexical_cast(asset_type_output_index) + "), but key does not exist (current height " + boost::lexical_cast(height()) + ")").c_str()))); } else if (get_result) throw0(DB_ERROR(lmdb_error("Error attempting to retrieve an output id by asset type output id from the db", get_result).c_str())); diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index 536a0c64c..dd7faaa90 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -645,6 +645,20 @@ namespace cryptonote }; //--------------------------------------------------------------- + struct origin_data + { + uint8_t tx_type; + crypto::public_key tx_pub_key; + crypto::key_image input_k_image; + crypto::ec_scalar uniqueness; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(tx_type) + FIELD(tx_pub_key) + FIELD(input_k_image) + //FIELD(uniqueness) + END_SERIALIZE() + }; } namespace std { diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 5382816c1..654ece579 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -289,7 +289,7 @@ namespace cryptonote return is_v1_tx(blobdata_ref{tx_blob.data(), tx_blob.size()}); } //--------------------------------------------------------------- - bool generate_key_image_helper(const account_keys& ack, const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector& additional_tx_public_keys, size_t real_output_index, const crypto::ec_scalar& uniqueness, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const origin_data& origin_tx_data) { crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation); @@ -314,13 +314,14 @@ namespace cryptonote } } - boost::optional subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, uniqueness,hwdev); + boost::optional subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index, origin_tx_data.uniqueness, hwdev); CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address"); - return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, uniqueness, subaddr_recv_info->index, in_ephemeral, ki, hwdev); + //assert(false); + return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev, origin_tx_data); } //--------------------------------------------------------------- - bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const cryptonote::transaction_type& tx_type, const crypto::ec_scalar& uniqueness, const crypto::public_key& pk_change_tx) + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const origin_data& origin_tx_data) { if (hwdev.compute_key_image(ack, out_key, recv_derivation, real_output_index, received_index, in_ephemeral, ki)) { @@ -355,8 +356,7 @@ namespace cryptonote } } - if (tx_type == cryptonote::transaction_type::PROTOCOL) { - + if (origin_tx_data.tx_type == (uint8_t)(cryptonote::transaction_type::PROTOCOL)) { /** * Okay so PROTOCOL_TX payments are triggered by a previously-made CONVERT or YIELD transaction. * The math works as follows (I will use a CONVERT TX as an example): @@ -396,11 +396,11 @@ namespace cryptonote // 2. Obtain a separate key_derivation for the _original_ P_change output // (using the TX public key from the CONVERT TX and the sender's private view key) crypto::key_derivation derivation_P_change_tx = AUTO_VAL_INIT(derivation_P_change_tx); - CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(pk_change_tx, ack.m_view_secret_key, derivation_P_change_tx), false, "Failed to generate key_derivation for P_change"); + CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(origin_tx_data.tx_pub_key, ack.m_view_secret_key, derivation_P_change_tx), false, "Failed to generate key_derivation for P_change"); // 3. Calculate the secret spend key "x_change" for the change output of the CONVERT TX crypto::secret_key sk_spend = crypto::null_skey; - CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation_P_change_tx, uniqueness, spend_skey, sk_spend), false, "Failed to derive secret key for P_change"); + CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation_P_change_tx, origin_tx_data.uniqueness, spend_skey, sk_spend), false, "Failed to derive secret key for P_change"); // 4. Derive the public key from the secret key for verification purposes crypto::public_key change_pk; @@ -409,7 +409,6 @@ namespace cryptonote // 5. Calculate the secret spend key "x_return" CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, real_output_index, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'"); - //CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, uniqueness, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'"); in_ephemeral.sec = scalar_step1; CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive one-time output public key 'P_return'"); CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key, @@ -418,13 +417,11 @@ namespace cryptonote // 6. Create the key_image needed to be able to spend the output hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); return true; - - } else { - - // computes Hs(a*R || uniqueness) + b - hwdev.derive_secret_key(recv_derivation, uniqueness, spend_skey, scalar_step1); } + // computes Hs(a*R || uniqueness) + b + hwdev.derive_secret_key(recv_derivation, origin_tx_data.uniqueness, spend_skey, scalar_step1); + // step 2: add Hs(a || index_major || index_minor) crypto::secret_key subaddr_sk; crypto::secret_key scalar_step2; @@ -448,7 +445,7 @@ namespace cryptonote else { // when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation - CHECK_AND_ASSERT_MES(hwdev.derive_public_key(recv_derivation, uniqueness, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key"); + CHECK_AND_ASSERT_MES(hwdev.derive_public_key(recv_derivation, origin_tx_data.uniqueness, ack.m_account_address.m_spend_public_key, in_ephemeral.pub), false, "Failed to derive public key"); // and don't forget to add the contribution from the subaddress part if (!received_index.is_zero()) { @@ -465,6 +462,7 @@ namespace cryptonote hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); return true; } + /* //--------------------------------------------------------------- bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const crypto::ec_scalar& uniqueness, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) { @@ -503,8 +501,6 @@ namespace cryptonote // computes Hs(a*R || uniqueness) + b hwdev.derive_secret_key(recv_derivation, uniqueness, spend_skey, scalar_step1); - LOG_ERROR("Cryptonote::" << __func__ << ":" << __LINE__); - LOG_ERROR("Break here"); // step 2: add Hs(a || index_major || index_minor) crypto::secret_key subaddr_sk; @@ -546,6 +542,7 @@ namespace cryptonote hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki); return true; } + */ //--------------------------------------------------------------- uint64_t power_integral(uint64_t a, uint64_t b) { @@ -1386,20 +1383,11 @@ namespace cryptonote bool r = acc.get_device().generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation); CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); - LOG_ERROR("*****************************************************************************"); - LOG_ERROR("derivation: " << derivation); - LOG_ERROR("uniqueness: " << uniqueness.data); - LOG_ERROR("txkey_pub : " << tx_pub_key); - crypto::public_key pk; if (out_can_be_to_acc(view_tag_opt, derivation, output_index, &acc.get_device())) { r = acc.get_device().derive_public_key(derivation, uniqueness, acc.m_account_address.m_spend_public_key, pk); CHECK_AND_ASSERT_MES(r, false, "Failed to derive public key"); - - LOG_ERROR("output_key: " << pk); - LOG_ERROR("*****************************************************************************"); - if (pk == output_public_key) return true; } @@ -1423,13 +1411,6 @@ namespace cryptonote boost::optional is_out_to_acc_precomp(const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector& additional_derivations, size_t output_index, const crypto::ec_scalar& uniqueness, hw::device &hwdev, const boost::optional& view_tag_opt) { LOG_ERROR("Cryptonote::" << __func__ << ":" << __LINE__); - //assert(false); - - LOG_ERROR("*****************************************************************************"); - LOG_ERROR("derivation: " << derivation); - //LOG_ERROR("uniqueness: " << uniqueness.data); - LOG_ERROR("out_key : " << out_key); - LOG_ERROR("*****************************************************************************"); // try the shared tx pubkey crypto::public_key subaddress_spendkey; @@ -1448,17 +1429,6 @@ namespace cryptonote if (out_can_be_to_acc(view_tag_opt, additional_derivations[output_index], output_index, &hwdev)) { CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key"); - - LOG_ERROR("*****************************************************************************"); - LOG_ERROR("derivation: " << additional_derivations[output_index]); - LOG_ERROR("output_ind: " << output_index); - LOG_ERROR("uniqueness: " << string_tools::pod_to_hex(uniqueness.data)); - LOG_ERROR("output_key: " << out_key); - LOG_ERROR("subaddr_sp: " << subaddress_spendkey); - LOG_ERROR("*****************************************************************************"); - - - auto found = subaddresses.find(subaddress_spendkey); if (found != subaddresses.end()) return subaddress_receive_info{ found->second, additional_derivations[output_index] }; @@ -1469,6 +1439,7 @@ namespace cryptonote //--------------------------------------------------------------- boost::optional is_out_to_acc_precomp(const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector& additional_derivations, const crypto::ec_scalar& uniqueness, hw::device &hwdev, const boost::optional& view_tag_opt) { + assert(false); LOG_ERROR("Cryptonote::" << __func__ << ":" << __LINE__); LOG_ERROR("Break here"); diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index f6c3e4de2..905e7bdc1 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -107,9 +107,9 @@ namespace cryptonote */ bool get_tx_fee(const transaction& tx, uint64_t & fee); uint64_t get_tx_fee(const transaction& tx); - bool generate_key_image_helper(const account_keys& ack, const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector& additional_tx_public_keys, size_t real_output_index, const crypto::ec_scalar& uniqueness, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); - bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const crypto::ec_scalar& uniqueness, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); - bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const cryptonote::transaction_type& tx_type, const crypto::ec_scalar& uniqueness, const crypto::public_key& pk_change_tx = crypto::null_pkey); + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const origin_data& origin_tx_data); + bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const cryptonote::origin_data& origin_tx_data); + // bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const crypto::ec_scalar& uniqueness, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); void get_blob_hash(const blobdata& blob, crypto::hash& res); void get_blob_hash(const blobdata_ref& blob, crypto::hash& res); crypto::hash get_blob_hash(const blobdata& blob); diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index b790199cc..b6fd8157d 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2534,9 +2534,16 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA return false; } const uint8_t hf_version = m_hardfork->get_current_version(); - for (const auto &t: data) + for (const auto &t: data) { + if (!req.asset_type.empty()) { + if (t.asset_type not_eq cryptonote::asset_id_from_type(req.asset_type)) { + MERROR("Invalid asset type - expected " << req.asset_type << ", but output is " << cryptonote::asset_type_from_id(t.asset_type)); + return false; + } + } res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time, hf_version), t.height, crypto::null_hash}); - + } + if (req.get_txid) { for (size_t i = 0; i < req.outputs.size(); ++i) diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 3be29f12c..76b500c0f 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -554,11 +554,12 @@ namespace cryptonote assert(false); } + /* // Print out the uniqueness crypto::public_key pk_uniq; std::memcpy(pk_uniq.data, uniqueness.data, sizeof(crypto::public_key)); LOG_ERROR("*** UNIQUENESS : " << pk_uniq); - + */ return true; } //--------------------------------------------------------------- @@ -580,8 +581,8 @@ namespace cryptonote CHECK_AND_ASSERT_MES(r, false, "at get_return_address: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")"); ec_scalar y = uniqueness; - LOG_ERROR("Break here"); /* + LOG_ERROR("Break here"); if (type == cryptonote::TRANSFER) { // TRANSFER relies on a shared secret (the key_derivation Z_i) between sender and recipient // y = Hs(uniqueness || z_i) @@ -619,7 +620,8 @@ namespace cryptonote rct::key key_verify = rct::scalarmultKey(key_test, key_y); CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach"); F = rct::rct2pk(key_test); - + + /* LOG_ERROR("*****************************************************************************"); LOG_ERROR("uniqueness: " << uniqueness.data); LOG_ERROR("txkey_pub : " << txkey_pub); @@ -629,6 +631,7 @@ namespace cryptonote LOG_ERROR("aP_change : " << pk_aP_change); LOG_ERROR("F : " << F); LOG_ERROR("*****************************************************************************"); + */ return true; } @@ -809,13 +812,9 @@ namespace cryptonote in_contexts.push_back(input_generation_context_data()); keypair& in_ephemeral = in_contexts.back().in_ephemeral; crypto::key_image img; - /* - // Calculate the uniqueness - size_t output_index_wrapper = src_entr.real_output_in_tx_index; - crypto::hash uniqueness = cn_fast_hash(reinterpret_cast(&output_index_wrapper), sizeof(size_t)); - */ + const auto& out_key = reinterpret_cast(src_entr.outputs[src_entr.real_output].second.dest); - if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, src_entr.uniqueness, in_ephemeral,img, hwdev)) + if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, src_entr.origin_tx_data)) { LOG_ERROR("Key image generation failed!"); return false; diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 7cfc22709..52b344ead 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -64,6 +64,7 @@ namespace cryptonote crypto::public_key P_change; crypto::key_image input_k_image; }; + 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 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); @@ -84,7 +85,7 @@ namespace cryptonote rct::multisig_kLRki multisig_kLRki; //multisig info oracle::pricing_record pr; std::string asset_type; - crypto::ec_scalar uniqueness; //the uniqueness needed to prove ownership of the consumed output + origin_data origin_tx_data; void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); } @@ -99,6 +100,7 @@ namespace cryptonote FIELD(mask) FIELD(multisig_kLRki) FIELD(asset_type) + FIELD(origin_tx_data) if (real_output >= outputs.size()) return false; diff --git a/src/multisig/multisig.cpp b/src/multisig/multisig.cpp index 42d27c04a..6fdb71fd6 100644 --- a/src/multisig/multisig.cpp +++ b/src/multisig/multisig.cpp @@ -99,9 +99,12 @@ namespace multisig // - later, we add in the components held by other participants cryptonote::keypair in_ephemeral; //crypto::hash uniqueness = crypto::cn_fast_hash(reinterpret_cast(&real_output_index), sizeof(size_t)); - crypto::ec_scalar uniqueness; + + // Populate this struct if you want to make use of multisig for Fulmo!!! assert(false); - if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, uniqueness, in_ephemeral, ki, keys.get_device())) + cryptonote::origin_data origin_tx_data; + + if (!cryptonote::generate_key_image_helper(keys, subaddresses, out_key, tx_public_key, additional_tx_public_keys, real_output_index, in_ephemeral, ki, keys.get_device(), origin_tx_data)) return false; std::unordered_set used; diff --git a/src/multisig/multisig_tx_builder_ringct.cpp b/src/multisig/multisig_tx_builder_ringct.cpp index e62656af9..e96288078 100644 --- a/src/multisig/multisig_tx_builder_ringct.cpp +++ b/src/multisig/multisig_tx_builder_ringct.cpp @@ -109,9 +109,10 @@ static bool compute_keys_for_sources( if (src.real_output >= src.outputs.size()) return false; - // Get the uniqueness for this TX - crypto::ec_scalar uniqueness; + // Populate this struct if you want to make use of multisig for Fulmo!!! assert(false); + cryptonote::origin_data origin_tx_data; + if (not cryptonote::generate_key_image_helper( account_keys, subaddresses, @@ -119,10 +120,10 @@ static bool compute_keys_for_sources( src.real_out_tx_key, src.real_out_additional_tx_keys, src.real_output_in_tx_index, - uniqueness, tmp_keys, tmp_key_image, - hwdev + hwdev, + origin_tx_data )) { return false; } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 3d4cebda8..5b1ade473 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -2556,6 +2556,7 @@ namespace cryptonote else KV_SERIALIZE_N(data.distribution, "distribution") KV_SERIALIZE_N(data.base, "base") + KV_SERIALIZE_N(data.num_spendable_global_outs, "num_spendable_global_outs") END_KV_SERIALIZE_MAP() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index df933c8ce..776de81aa 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -6422,7 +6422,7 @@ bool simple_wallet::process_ring_members(const std::vectorget_rpc_client_secret_key()); - req.asset_type = td.asset_type; + //req.asset_type = td.asset_type; bool r = m_wallet->invoke_http_bin("/get_outs.bin", req, res); err = interpret_rpc_response(r, res.status); if (!err.empty()) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index ac8dc0549..b531ded18 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2022, The Monero Project +/// Copyright (c) 2014-2022, The Monero Project // // All rights reserved. // @@ -1878,7 +1878,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons THROW_WALLET_EXCEPTION_IF(!get_output_public_key(tx.vout[i], output_public_key), error::wallet_internal_error, "Failed to get output public key"); // Is this a payout from a PROTOCOL_TX? - crypto::public_key pk_change_tx = crypto::null_pkey; + cryptonote::origin_data origin_tx_data; if (tx.type == cryptonote::transaction_type::PROTOCOL) { // Calculate the subaddress public_key (P_change) @@ -1891,20 +1891,24 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate protocol_tx entry to permit source usage"); size_t idx = search->second; THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers"); - const transfer_details& td = get_transfer_details(idx); - THROW_WALLET_EXCEPTION_IF(td.m_tx.type != cryptonote::transaction_type::CONVERT && td.m_tx.type != cryptonote::transaction_type::YIELD, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers"); - pk_change_tx = get_tx_pub_key_from_extra(td.m_tx); + const transfer_details& td_origin = get_transfer_details(idx); + THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::CONVERT && td_origin.m_tx.type != cryptonote::transaction_type::YIELD, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers"); + origin_tx_data.tx_type = (uint8_t)(tx.type); + origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx); // Create a "uniqueness" value - both CONVERT and YIELD use the same uniqueness format, based on the first input key_image - THROW_WALLET_EXCEPTION_IF(td.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided"); - THROW_WALLET_EXCEPTION_IF(td.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "tx.vin[0] in origin TX must be of type txin_to_key"); - crypto::key_image k_image = boost::get(td.m_tx.vin[0]).k_image; - THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td.m_tx.type, k_image, td.m_block_height, i, tx_scan_info.uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); + THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided"); + THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "tx.vin[0] in origin TX must be of type txin_to_key"); + origin_tx_data.input_k_image = boost::get(td_origin.m_tx.vin[0]).k_image; + THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td_origin.m_tx.type, origin_tx_data.input_k_image, td_origin.m_block_height, i, origin_tx_data.uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); } else { // Expect a uniqueness value to have been provided by tx_scan_info LOG_ERROR("DEBUG HERE"); + origin_tx_data.tx_type = (uint8_t)(tx.type); + origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(tx); + origin_tx_data.uniqueness = tx_scan_info.uniqueness; } if (m_multisig) @@ -1915,7 +1919,7 @@ void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, cons } else { - bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device(), tx.type, tx_scan_info.uniqueness, pk_change_tx); + bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), output_public_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device(), origin_tx_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != output_public_key, error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); @@ -2434,11 +2438,15 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (!pool) { transfer_details &td = m_transfers[kit->second]; - td.m_block_height = height; - td.m_internal_output_index = o; - td.m_global_output_index = o_indices[o]; - td.m_tx = (const cryptonote::transaction_prefix&)tx; - td.m_txid = txid; + td.m_block_height = height; + td.m_internal_output_index = o; + td.m_global_output_index = o_indices[o]; + td.m_tx = (const cryptonote::transaction_prefix&)tx; + td.m_txid = txid; + std::string asset_type = ""; + THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_asset_type(tx.vout[o], asset_type), error::wallet_internal_error, "failed to get output_asset_type"); + td.m_asset_type_output_index = asset_type_output_indices[o]; + td.asset_type = asset_type; td.m_amount = amount; td.m_pk_index = pk_index - 1; td.m_subaddr_index = tx_scan_info[o].received->index; @@ -3920,7 +3928,7 @@ bool wallet2::refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& rece return ok; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_rct_distribution(const std::string &rct_asset_type, uint64_t &start_height, std::vector &distribution) +bool wallet2::get_rct_distribution(const bool use_global_outs, const std::string &rct_asset_type, uint64_t &start_height, std::vector &distribution, uint64_t &num_spendable_global_outs) { MDEBUG("Requesting rct distribution"); @@ -3931,7 +3939,8 @@ bool wallet2::get_rct_distribution(const std::string &rct_asset_type, uint64_t & req.cumulative = false; req.binary = true; req.compress = true; - req.rct_asset_type = rct_asset_type; + if (!use_global_outs) + req.rct_asset_type = rct_asset_type; bool r; try @@ -3957,6 +3966,7 @@ bool wallet2::get_rct_distribution(const std::string &rct_asset_type, uint64_t & MWARNING("Failed to request output distribution: results are not for amount 0"); return false; } + num_spendable_global_outs = res.distributions[0].data.num_spendable_global_outs; for (size_t i = 1; i < res.distributions[0].data.distribution.size(); ++i) res.distributions[0].data.distribution[i] += res.distributions[0].data.distribution[i-1]; start_height = res.distributions[0].data.start_height; @@ -6252,7 +6262,7 @@ std::map wallet2::balance_per_subaddress(uint32_t index_majo for (const auto& utx: m_unconfirmed_payments) { - if (utx.second.m_pd.m_subaddr_index.major == index_major) + if (utx.second.m_pd.m_subaddr_index.major == index_major && utx.second.m_pd.m_asset_type == asset_type) { amount_per_subaddr[utx.second.m_pd.m_subaddr_index.minor] += utx.second.m_pd.m_amount; } @@ -7101,35 +7111,23 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector(tx.vin[0]).k_image; + origin_tx_data.input_k_image = boost::get(tx.vin[0]).k_image; } crypto::ec_scalar uniqueness; - THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(tx.type, k_image, ((size_t)(-1)), i, uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); - //assert(false); - /* - crypto::hash uniqueness = crypto::null_hash; - if (tx.type == cryptonote::transaction_type::MINER) { - uniqueness = cn_fast_hash(reinterpret_cast(&i), sizeof(size_t)); - } else if (tx.type == cryptonote::transaction_type::TRANSFER) { - const txin_to_key &in = boost::get(tx.vin[0]); - uniqueness = cn_fast_hash(reinterpret_cast(&in.k_image.data[0]), 32); - } else if (tx.type == cryptonote::transaction_type::CONVERT) { - const txin_to_key &in = boost::get(tx.vin[0]); - uniqueness = cn_fast_hash(reinterpret_cast(&in.k_image.data[0]), 32); - } else { - uniqueness = cn_fast_hash(reinterpret_cast(&i), sizeof(size_t)); - } - */ + THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(tx.type, origin_tx_data.input_k_image, ((size_t)(-1)), i, origin_tx_data.uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); + // if this output is back to this wallet, we can calculate its key image already if (!is_out_to_acc_precomp(m_subaddresses, output_public_key, derivation, additional_derivations, i, uniqueness, hwdev, get_output_view_tag(tx.vout[i]))) continue; crypto::key_image ki; cryptonote::keypair in_ephemeral; //crypto::hash uniqueness = cn_fast_hash(reinterpret_cast(&i), sizeof(size_t)); - if (generate_key_image_helper(keys, m_subaddresses, output_public_key, tx_pub_key, additional_tx_pub_keys, i, uniqueness, in_ephemeral, ki, hwdev)) + if (generate_key_image_helper(keys, m_subaddresses, output_public_key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev, origin_tx_data)) signed_txes.tx_key_images[output_public_key] = ki; else MERROR("Failed to calculate key image"); @@ -8281,10 +8279,12 @@ std::pair, size_t> outs_unique(const std::vector> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, bool rct, std::unordered_set &valid_public_keys_cache) { + uint64_t num_outs_per_asset = 0; + uint64_t num_spendable_global_outs = 0; std::vector rct_offsets; for (size_t attempts = 3; attempts > 0; --attempts) { - get_outs(outs, selected_transfers, fake_outputs_count, rct_offsets, valid_public_keys_cache); + get_outs(outs, selected_transfers, fake_outputs_count, rct_offsets, valid_public_keys_cache, num_spendable_global_outs, num_outs_per_asset); if (!rct) return; @@ -8306,7 +8306,7 @@ void wallet2::get_outs(std::vector> THROW_WALLET_EXCEPTION(error::wallet_internal_error, tr("Transaction sanity check failed")); } -void wallet2::get_outs(std::vector> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, std::vector &rct_offsets, std::unordered_set &valid_public_keys_cache) +void wallet2::get_outs(std::vector> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, std::vector &rct_offsets, std::unordered_set &valid_public_keys_cache, uint64_t &num_spendable_global_outs, uint64_t &num_outs) { LOG_PRINT_L2("fake_outputs_count: " << fake_outputs_count); outs.clear(); @@ -8327,6 +8327,7 @@ void wallet2::get_outs(std::vector> // if we have at least one rct out, get the distribution, or fall back to the previous system uint64_t rct_start_height; bool has_rct = false; + bool use_global_outs = false; uint64_t max_rct_index = 0; std::string rct_asset_type = m_transfers[selected_transfers[0]].asset_type; for (size_t idx: selected_transfers) { @@ -8334,13 +8335,20 @@ void wallet2::get_outs(std::vector> THROW_WALLET_EXCEPTION_IF(m_transfers[idx].asset_type != rct_asset_type, error::wallet_internal_error, "selected_transfer entry has wrong asset_type"); if (m_transfers[idx].is_rct()) { + // use_global_outs should either always be true or false, because the single rct distribution requested in get_rct_distribution below + // will either be the distribution of all global outputs, or the distribution of outputs by asset type. This check makes + // sure the use_global_outs boolean will not be flipped when set in the next line. + //THROW_WALLET_EXCEPTION_IF(has_rct && ((use_global_outs && m_transfers[idx].m_asset_type_output_index_known) || (!use_global_outs && !m_transfers[idx].m_asset_type_output_index_known)), + // error::wallet_internal_error, "Mismatch of global outputs and asset type outputs"); + has_rct = true; - max_rct_index = std::max(max_rct_index, m_transfers[idx].m_asset_type_output_index); + //use_global_outs = !m_transfers[idx].m_asset_type_output_index_known; + max_rct_index = std::max(max_rct_index, use_global_outs ? m_transfers[idx].m_global_output_index : m_transfers[idx].m_asset_type_output_index); } } if (has_rct && rct_offsets.empty()) { - THROW_WALLET_EXCEPTION_IF(!get_rct_distribution(rct_asset_type, rct_start_height, rct_offsets), + THROW_WALLET_EXCEPTION_IF(!get_rct_distribution(use_global_outs, rct_asset_type, rct_start_height, rct_offsets, num_spendable_global_outs), error::get_output_distribution, "Could not obtain output distribution."); } @@ -8547,6 +8555,14 @@ void wallet2::get_outs(std::vector> LOG_PRINT_L1("" << num_outs << " unlocked rct outputs"); THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error, "histogram reports no unlocked rct outputs, not even ours"); + + // When num_spendable_global_outs is set, it means num_outs is the number of spendable outputs of a particular asset type. + // There can't possibly be more spendable outputs of a particular type than the global set of all spendable outputs + THROW_WALLET_EXCEPTION_IF(!use_global_outs && num_spendable_global_outs < num_outs, error::get_output_distribution, + "Daemon reports too few global outputs"); + + if (use_global_outs) + num_spendable_global_outs = num_outs; } // how many fake outs to draw on a pre-fork distribution @@ -8564,7 +8580,7 @@ void wallet2::get_outs(std::vector> recent_outputs_count = 1; // ensure we have at least one, if possible if (recent_outputs_count > num_recent_outs) recent_outputs_count = num_recent_outs; - if (td.m_global_output_index >= num_outs - num_recent_outs && recent_outputs_count > 0) + if (td.m_asset_type_output_index >= num_outs - num_recent_outs && recent_outputs_count > 0) --recent_outputs_count; // if the real out is recent, pick one less recent fake out } LOG_PRINT_L1("Fake output makeup: " << requested_outputs_count << " requested: " << recent_outputs_count << " recent, " << @@ -8594,7 +8610,7 @@ void wallet2::get_outs(std::vector> if (out < num_outs) { MINFO("Using it"); - req.outputs.push_back({amount, out}); + req.outputs.push_back({amount, out, true}); // Rings are stored referencing global output IDs ++num_found; seen_indices.emplace(out); if (out == td.m_global_output_index) @@ -8629,9 +8645,10 @@ void wallet2::get_outs(std::vector> if (num_found == 0) { num_found = 1; - seen_indices.emplace(td.m_global_output_index); - req.outputs.push_back({amount, td.m_global_output_index}); - LOG_PRINT_L1("Selecting real output: " << td.m_global_output_index << " for " << print_money(amount)); + uint64_t o_index = use_global_outs ? td.m_global_output_index : td.m_asset_type_output_index; + seen_indices.emplace(o_index); + req.outputs.push_back({amount, o_index}); + LOG_PRINT_L1("Selecting real output: " << td.m_global_output_index << "/" << td.m_asset_type_output_index << " for " << print_money(amount)); } std::unordered_map> picks; @@ -8781,7 +8798,8 @@ void wallet2::get_outs(std::vector> COMMAND_RPC_GET_OUTPUTS_BIN::request chunk_req = AUTO_VAL_INIT(chunk_req); COMMAND_RPC_GET_OUTPUTS_BIN::response chunk_daemon_resp = AUTO_VAL_INIT(chunk_daemon_resp); chunk_req.get_txid = false; - chunk_req.asset_type = rct_asset_type; + if (!use_global_outs) + chunk_req.asset_type = rct_asset_type; const size_t this_chunk_size = std::min(req.outputs.size() - offset, chunk_size); chunk_req.outputs.reserve(this_chunk_size); for (size_t i = 0; i < this_chunk_size; ++i) @@ -8839,7 +8857,7 @@ void wallet2::get_outs(std::vector> for (size_t n = 0; n < requested_outputs_count; ++n) { size_t i = base + n; - if (daemon_resp.outs[i].output_id == td.m_global_output_index) + if ((use_global_outs ? req.outputs[i].index : daemon_resp.outs[i].output_id) == td.m_global_output_index) if (daemon_resp.outs[i].key == td.get_public_key()) if (daemon_resp.outs[i].mask == mask) if (daemon_resp.outs[i].unlocked) @@ -8860,7 +8878,7 @@ void wallet2::get_outs(std::vector> const std::vector &ring = it->second; for (uint64_t out: ring) { - if (out < num_outs) + if (out < num_spendable_global_outs) { if (out != td.m_global_output_index) { @@ -8868,7 +8886,7 @@ void wallet2::get_outs(std::vector> for (size_t o = 0; o < requested_outputs_count; ++o) { size_t i = base + o; - if (req.outputs[i].index == out) + if (req.outputs[i].index == out && req.outputs[i].is_global_out) { LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key << " (from existing ring)"); tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache); @@ -8896,7 +8914,7 @@ void wallet2::get_outs(std::vector> { size_t i = base + order[o]; LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key); - tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache); + tx_add_fake_output(outs, (use_global_outs ? req.outputs[i].index : daemon_resp.outs[i].output_id), daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache); } if (outs.back().size() < fake_outputs_count + 1) { @@ -9248,55 +9266,55 @@ void wallet2::transfer_selected_rct(std::vector additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); + THROW_WALLET_EXCEPTION_IF(additional_tx_pub_keys.size() < td.m_internal_output_index, error::wallet_internal_error, "failed to obtain additional tx pub keys for PROTOCOL TX"); + crypto::public_key protocol_tx_output_pub_key = additional_tx_pub_keys[td.m_internal_output_index]; + + // 2. Calculate the derivation we need - it's simply aR (secret view key * tx_pub_key) + crypto::key_derivation derivation_protocol_tx_output = AUTO_VAL_INIT(derivation_protocol_tx_output); + bool ok = get_account().get_device().generate_key_derivation(protocol_tx_output_pub_key, get_account().get_keys().m_view_secret_key, derivation_protocol_tx_output); + THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to create key_derivation aR for PROTOCOL TX"); + + // 3. Calculate the subaddress public_key (P_change) by deriving it from the output_public_key (the tx.vout[n] value) crypto::public_key output_public_key = td.get_public_key(); - auto search = m_protocol_txs.find(output_public_key); - THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate protocol_tx entry to permit source usage"); + crypto::public_key P_change = crypto::null_pkey; + ok = m_account.get_device().derive_subaddress_public_key(output_public_key, derivation_protocol_tx_output, td.m_internal_output_index/*i*/, P_change); + THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to derive subaddress public key for PROTOCOL TX"); + + // 4. Find the CONVERT/YIELD TX that created P_change + auto search = m_protocol_txs.find(P_change); + THROW_WALLET_EXCEPTION_IF(search == m_protocol_txs.end(), error::wallet_internal_error, "failed to locate m_protocol_txs entry to permit origin TX usage"); size_t idx = search->second; - THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers"); - const transfer_details& td2 = get_transfer_details(idx); - THROW_WALLET_EXCEPTION_IF(td2.m_tx.type != cryptonote::transaction_type::CONVERT && td2.m_tx.type != cryptonote::transaction_type::YIELD, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers"); + THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate m_protocol_txs index in m_transfers"); + const transfer_details& td_origin = get_transfer_details(idx); + THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::CONVERT && td_origin.m_tx.type != cryptonote::transaction_type::YIELD, + error::wallet_internal_error, + "incorrect TX type for protocol_tx origin in m_transfers"); - // We now have access to the sorted tx.vin vector - we need the key_image from the first entry to decode the public_key - THROW_WALLET_EXCEPTION_IF(td2.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "incorrect TX vin[0] type for protocol_tx origin in m_transfers"); - - const txin_to_key &in = boost::get(td2.m_tx.vin[0]); - crypto::key_image ki = in.k_image; + // 5. Create a "uniqueness" value and store the rest of the "origin_tx" data + // (both CONVERT and YIELD use the same uniqueness format, based on the first input key_image) + THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided"); + THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.vin[0].type() != typeid(cryptonote::txin_to_key), error::wallet_internal_error, "tx.vin[0] in origin TX must be of type txin_to_key"); + src.origin_tx_data.input_k_image = boost::get(td_origin.m_tx.vin[0]).k_image; + THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td_origin.m_tx.type, src.origin_tx_data.input_k_image, td_origin.m_block_height, td.m_internal_output_index, src.origin_tx_data.uniqueness), + error::wallet_internal_error, + "Failed to calculate uniqueness"); - crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(td2.m_tx); - THROW_WALLET_EXCEPTION_IF(tx_pub_key == null_pkey, error::wallet_internal_error, "Tx pubkey was not found"); + // 6. Store all of the origin_tx data + src.origin_tx_data.tx_type = ((uint8_t)td.m_tx.type); + src.origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx); - // Generate a derivation using the _correct_ TX pubkey - crypto::key_derivation convert_tx_derivation; - THROW_WALLET_EXCEPTION_IF(!generate_key_derivation(tx_pub_key, get_account().get_keys().m_view_secret_key, convert_tx_derivation), error::wallet_internal_error, "Failed to generate a derivation image"); - - // Derive a public key now, using the information we have - // SRCG: Calculate the correct uniqueness value here - THROW_WALLET_EXCEPTION_IF(td2.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided"); - crypto::key_image k_image; - if (td2.m_tx.vin[0].type() == typeid(cryptonote::txin_to_key)) { - k_image = boost::get(td2.m_tx.vin[0]).k_image; - } - crypto::ec_scalar uniqueness; - THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td2.m_tx.type, k_image, td2.m_block_height, i, uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); - assert(false); - crypto::public_key pk = crypto::null_pkey; - THROW_WALLET_EXCEPTION_IF(!m_account.get_device().derive_public_key(convert_tx_derivation, uniqueness, get_account().get_keys().m_account_address.m_spend_public_key, pk), error::wallet_internal_error, "Failed to derive a public key given the necessary key image"); - THROW_WALLET_EXCEPTION_IF(pk != output_public_key, error::wallet_internal_error, "public key derived from CONVERT_TX uniqueness does not match"); - src.uniqueness = uniqueness; } else { - //size_t output_index_wrapper = td.m_internal_output_index; - //src.uniqueness = cn_fast_hash(reinterpret_cast(&output_index_wrapper), sizeof(size_t)); + // SRCG: Calculate the correct uniqueness value here THROW_WALLET_EXCEPTION_IF(td.m_tx.vin.empty(), error::wallet_internal_error, "no tx.vin[] provided"); crypto::key_image k_image; if (td.m_tx.vin[0].type() == typeid(cryptonote::txin_to_key)) { k_image = boost::get(td.m_tx.vin[0]).k_image; } - THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td.m_tx.type, k_image, td.m_block_height, td.m_internal_output_index, src.uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); - LOG_ERROR("BREAK HERE"); - //assert(false); + THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td.m_tx.type, k_image, td.m_block_height, td.m_internal_output_index, src.origin_tx_data.uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); } //paste mixin transaction @@ -9337,23 +9355,6 @@ void wallet2::transfer_selected_rct(std::vectorsecond; - THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol_txs index in m_transfers"); - const transfer_details& td2 = get_transfer_details(idx); - THROW_WALLET_EXCEPTION_IF(td2.m_tx.type != cryptonote::transaction_type::CONVERT && td2.m_tx.type != cryptonote::transaction_type::YIELD, error::wallet_internal_error, "incorrect TX type for protocol_tx origin in m_transfers"); - real_oe.second.dest = rct::pk2rct(td2.get_public_key()); - src.real_out_tx_key = get_tx_pub_key_from_extra(td2.m_tx, td.m_pk_index); - src.real_out_additional_tx_keys = get_additional_tx_pub_keys_from_extra(td2.m_tx); - } - detail::print_source_entry(src); ++out_index; } @@ -11228,17 +11229,16 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string // derive the real output keypair const transfer_details& in_td = m_transfers[found->second]; - // SRCG: We KNOW it's a txin_to_key, so it's an RCT transaction, NOT a PROTOCOL transaction. - crypto::ec_scalar uniqueness; + // SRCG: Calculate the correct uniqueness value here assert(false); - //THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(tx, in_td.m_block_height, 0, uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness"); - + cryptonote::origin_data origin_tx_data; + crypto::public_key in_tx_out_pkey = in_td.get_public_key(); const crypto::public_key in_tx_pub_key = get_tx_pub_key_from_extra(in_td.m_tx, in_td.m_pk_index); const std::vector in_additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(in_td.m_tx); keypair in_ephemeral; crypto::key_image in_img; - THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey, in_tx_pub_key, in_additional_tx_pub_keys, in_td.m_internal_output_index, uniqueness, in_ephemeral, in_img, m_account.get_device()), + THROW_WALLET_EXCEPTION_IF(!generate_key_image_helper(m_account.get_keys(), m_subaddresses, in_tx_out_pkey, in_tx_pub_key, in_additional_tx_pub_keys, in_td.m_internal_output_index, in_ephemeral, in_img, m_account.get_device(), origin_tx_data), error::wallet_internal_error, "failed to generate key image"); THROW_WALLET_EXCEPTION_IF(in_key->k_image != in_img, error::wallet_internal_error, "key image mismatch"); @@ -12008,12 +12008,15 @@ std::string wallet2::get_reserve_proof(const boost::optional> //uniqueness = cn_fast_hash(reinterpret_cast(&output_index_wrapper), sizeof(size_t)); } + // Populate this struct if you want to make use of check_reserve_proof() for Fulmo!!! + assert(false); + cryptonote::origin_data origin_tx_data; + // generate ephemeral secret key crypto::key_image ki; cryptonote::keypair in_ephemeral; - bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, uniqueness, in_ephemeral, ki, m_account.get_device()); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, pkey, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, ki, m_account.get_device(), origin_tx_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); THROW_WALLET_EXCEPTION_IF(td.m_key_image_known && !td.m_key_image_partial && ki != td.m_key_image, @@ -13273,7 +13280,6 @@ process: crypto::ec_scalar uniqueness; if (td.m_tx.type == cryptonote::MINER) { THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td.m_tx.type, k_image, td.m_block_height, td.m_internal_output_index, uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness (MINER)"); - assert(false); //size_t uniqueness_wrapper = td.m_block_height; //uniqueness = cn_fast_hash(reinterpret_cast(&uniqueness_wrapper), sizeof(size_t)); } else if (td.m_tx.type == cryptonote::PROTOCOL) { @@ -13286,10 +13292,13 @@ process: THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Failed to generate uniqueness - wallet2::import_outputs()"); } else { THROW_WALLET_EXCEPTION_IF(!cryptonote::calculate_uniqueness(td.m_tx.type, k_image, td.m_block_height, td.m_internal_output_index, uniqueness), error::wallet_internal_error, "Failed to calculate uniqueness (MINER)"); - assert(false); //size_t output_index_wrapper = td.m_internal_output_index; //uniqueness = cn_fast_hash(reinterpret_cast(&output_index_wrapper), sizeof(size_t)); } + + // Populate this struct if you want to make use of "import_outputs" for Fulmo!!! + assert(false); + origin_data origin_tx_data; // the hot wallet wouldn't have known about key images (except if we already exported them) cryptonote::keypair in_ephemeral; @@ -13303,7 +13312,7 @@ process: crypto::public_key out_key = td.get_public_key(); if (should_expand(td.m_subaddr_index)) create_one_off_subaddress(td.m_subaddr_index); - bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, uniqueness, in_ephemeral, td.m_key_image, m_account.get_device()); + bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device(), origin_tx_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); if (should_expand(td.m_subaddr_index)) expand_subaddresses(td.m_subaddr_index); @@ -13429,6 +13438,10 @@ size_t wallet2::import_outputs(const std::tuple(&output_index_wrapper), sizeof(size_t)); } + // Populate this struct if you want to make use of "import_outputs" for Fulmo!!! + assert(false); + origin_data origin_tx_data; + // the hot wallet wouldn't have known about key images (except if we already exported them) cryptonote::keypair in_ephemeral; @@ -13437,7 +13450,7 @@ size_t wallet2::import_outputs(const std::tuple> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, bool rct, std::unordered_set &valid_public_keys_cache); - void get_outs(std::vector> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, std::vector &rct_offsets, std::unordered_set &valid_public_keys_cache); + void get_outs(std::vector> &outs, const std::vector &selected_transfers, size_t fake_outputs_count, std::vector &rct_offsets, std::unordered_set &valid_public_keys_cache, uint64_t &num_spendable_global_outs, uint64_t &num_outs); bool tx_add_fake_output(std::vector> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked, std::unordered_set &valid_public_keys_cache) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector &unused_transfers_indices, const std::vector &unused_dust_indices) const; std::vector get_only_rct(const std::vector &unused_dust_indices, const std::vector &unused_transfers_indices) const; @@ -1763,7 +1763,7 @@ private: void register_devices(); hw::device& lookup_device(const std::string & device_descriptor); - bool get_rct_distribution(const std::string &rct_asset_type, uint64_t &start_height, std::vector &distribution); + bool get_rct_distribution(const bool use_global_outs, const std::string &rct_asset_type, uint64_t &start_height, std::vector &distribution, uint64_t &num_spendable_global_outs); uint64_t get_segregation_fork_height() const;