From 0b835903ab7a404fe193107387a5040050a2b0e2 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Sat, 5 Aug 2023 20:27:46 +0200 Subject: [PATCH] asset operations in for wallet --- src/currency_core/blockchain_storage.cpp | 4 +- src/currency_core/currency_format_utils.cpp | 147 +++++++++++++++----- src/currency_core/currency_format_utils.h | 2 + src/wallet/wallet2.cpp | 109 ++++++++------- src/wallet/wallet2.h | 1 + 5 files changed, 176 insertions(+), 87 deletions(-) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 69d4f316..4419e105 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -3816,7 +3816,7 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a { // asset_id = AUTO_VAL_INIT(asset_id); // CHECK_AND_ASSERT_MES(validate_asset_operation_balance_proof(tx, tx_id, ado, asset_id), false, "asset operation validation failed!"); - CHECK_AND_ASSERT_MES(ado.op_proof.has_value(), false, "Ownership validation failed - missing signature"); + CHECK_AND_ASSERT_MES(ado.opt_proof.has_value(), false, "Ownership validation failed - missing signature"); CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << asset_id << " has invalid history size() == 0"); @@ -3826,7 +3826,7 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a normalize_asset_operation_for_hashing(ado_local); std::string buff = t_serializable_object_to_blob(ado_local); crypto::hash h = crypto::cn_fast_hash(buff.data(), buff.size()); - return crypto::check_signature(h, owner_key, *ado.op_proof); + return crypto::check_signature(get_signature_hash_for_asset_operation(ado), owner_key, *ado.opt_proof); } //------------------------------------------------------------------ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 2034f3c5..e0edf3a4 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -1113,12 +1113,19 @@ namespace currency string_tools::append_pod_to_strbuff(origin_blob, origin_hs); return origin_blob; } + //--------------------------------------------------------------- + crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado) + { + asset_descriptor_operation ado_local = ado; + normalize_asset_operation_for_hashing(ado_local); + std::string buff = t_serializable_object_to_blob(ado_local); + return crypto::cn_fast_hash(buff.data(), buff.size()); + } //--------------------------------------------------------------- - void normalize_asset_operation_for_hashing(asset_descriptor_operation& op) { - op.op_proof = boost::none; + op.opt_proof = boost::none; } //--------------------------------------------------------------- @@ -2072,6 +2079,110 @@ namespace currency p_result_point->to_public_key(*p_result_pub_key); } + bool construct_tx_handle_ado(const account_keys& sender_account_keys, const finalize_tx_param& ftp, asset_descriptor_operation* pado, tx_generation_context& gen_context) + { + if (pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) + { + //CHECK_AND_ASSERT_MES(pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unsupported asset operation: " << (int)pado->operation_type); + crypto::secret_key asset_control_key{}; + bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_tx_secret_key, asset_control_key, pado->descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY); + CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed"); + + calculate_asset_id(pado->descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id); + + // calculate amount blinding mask + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, asset_control_key); + + // set correct asset_id to the corresponding destination entries + uint64_t amount_of_emitted_asset = 0; + for (auto& item : shuffled_dsts) + { + if (item.asset_id == currency::null_pkey) + { + item.asset_id = gen_context.ao_asset_id; // set calculated asset_id to the asset's outputs, if this asset is being emitted within this tx + amount_of_emitted_asset += item.amount; + } + } + pado->descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle + + gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; + pado->opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + + } + else { + if (pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT) + { + + //bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_tx_secret_key, asset_control_key, pado->descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY); + //CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed"); + + //calculate_asset_id(pado->descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id); + CHECK_AND_ASSERT_MES(pado->opt_asset_id, false, "pado->opt_asset_id is not found at pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT/UPDATE"); + + gen_context.ao_asset_id = *pado->opt_asset_id; + gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id); + // calculate amount blinding mask + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key); + + // set correct asset_id to the corresponding destination entries + uint64_t amount_of_emitted_asset = 0; + for (auto& item : shuffled_dsts) + { + if (item.asset_id == gen_context.ao_asset_id) + { + amount_of_emitted_asset += item.amount; + } + } + pado->descriptor.current_supply += amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle + + gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; + pado->opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + + } + else if (pado->operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + CHECK_AND_ASSERT_MES(pado->opt_asset_id, false, "pado->opt_asset_id is not found at pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT/UPDATE"); + CHECK_AND_ASSERT_MES(pado->opt_proof, false, "pado->opt_asset_id is not found at pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT/UPDATE"); + CHECK_AND_ASSERT_MES(!pado->opt_amount_commitment, false, "pado->opt_asset_id is not found at pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT/UPDATE"); + + //fields that not supposed to be changed? + } + else if (pado->operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + + //calculate_asset_id(pado->descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id); + CHECK_AND_ASSERT_MES(pado->opt_asset_id, false, "pado->opt_asset_id is not found at pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT/UPDATE"); + + gen_context.ao_asset_id = *pado->opt_asset_id; + gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id); + // calculate amount blinding mask + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key); + + // set correct asset_id to the corresponding destination entries + uint64_t amount_of_burned_assets = 0; + for (auto& item : ftp.sources) + { + if (item.asset_id == gen_context.ao_asset_id) + { + amount_of_burned_assets += item.amount; + } + } + pado->descriptor.current_supply -= amount_of_burned_assets; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle + + gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; + pado->opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + } + + //seal it with owners signature + crypto::signature sig = currency::null_sig; + crypto::public_key pub_k = currency::null_pkey; + crypto::secret_key_to_public_key(ftp.asset_control_key, pub_k); + crypto::generate_signature(get_signature_hash_for_asset_operation(ado), ftp.asset_control_key, sig); + pado->opt_proof = sig; + } + return true; + } + bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& ftp, finalized_tx& result) { const std::vector& sources = ftp.sources; @@ -2325,36 +2436,8 @@ namespace currency pado = get_type_in_variant_container(tx.extra); if (pado) { - if (pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) - { - CHECK_AND_ASSERT_MES(pado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unsupported asset operation: " << (int)pado->operation_type); - crypto::secret_key asset_control_key{}; - bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_tx_secret_key, asset_control_key, pado->descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY); - CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed"); - - calculate_asset_id(pado->descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id); - - // calculate amount blinding mask - gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, asset_control_key); - - // set correct asset_id to the corresponding destination entries - uint64_t amount_of_emitted_asset = 0; - for (auto& item : shuffled_dsts) - { - if (item.asset_id == currency::null_pkey) - { - item.asset_id = gen_context.ao_asset_id; // set calculated asset_id to the asset's outputs, if this asset is being emitted within this tx - amount_of_emitted_asset += item.amount; - } - } - pado->descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle - - gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; - pado->opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); - - } - //LOG_PRINT_CYAN("AO " << ": " << crypto::scalar_t(amount_of_emitted_asset) << " x " << gen_context.ao_asset_id_pt << " + " << gen_context.ao_amount_blinding_mask << " x G", LOG_LEVEL_0); - //LOG_PRINT_CYAN(" == " << gen_context.ao_amount_commitment << ", x 1/8 == " << pado->opt_amount_commitment.get(), LOG_LEVEL_0); + bool r = construct_tx_handle_ado(sender_account_keys, ftp, pado, gen_context); + CHECK_AND_ASSERT_MES(r, false, "Failed to construct_tx_handle_ado()"); } } diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 2788de96..8311428e 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -158,6 +158,7 @@ namespace currency crypto::public_key spend_pub_key; // only for validations uint64_t tx_version; uint64_t mode_separate_fee = 0; + crypto::secret_key asset_control_key = currency::null_pkey; tx_generation_context gen_context{}; // solely for consolidated txs @@ -445,6 +446,7 @@ namespace currency std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys); void normalize_asset_operation_for_hashing(asset_descriptor_operation& op); + crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado); template typename std::conditional::value, const std::vector, std::vector >::type& get_txin_etc_options(t_txin_v& in) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 8d685b3a..3a737704 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -416,6 +416,54 @@ const crypto::public_key& wallet2::out_get_pub_key(const currency::tx_out_v& out } } //---------------------------------------------------------------------------------------------------- +void wallet2::process_ado_in_new_transaction(const asset_descriptor_operation& ado) +{ + do + { + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) + { + crypto::public_key self_check = AUTO_VAL_INIT(self_check); + crypto::secret_key asset_control_key = AUTO_VAL_INIT(asset_control_key); + bool r = derive_key_pair_from_key_pair(tx_pub_key, m_account.get_keys().spend_secret_key, asset_control_key, self_check, CRYPTO_HDS_ASSET_CONTROL_KEY); + if (!r) + { + //not critical error, continue to work + LOG_ERROR("Failed to derive_key_pair_from_key_pair for asset_descriptor_operation in tx " << ptc.tx_hash()); + break; + } + + if (self_check != ado.descriptor.owner) + { + //still not critical error + LOG_ERROR("Public key from asset_descriptor_operation(" << ado.descriptor.owner << ") not much with derived public key(" << self_check << "), for tx" << ptc.tx_hash()); + break; + } + crypto::public_key asset_id{}; + calculate_asset_id(ado.descriptor.owner, nullptr, &asset_id); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_own_asset_descriptors.count(asset_id) == 0, "asset with asset_id " << asset_id << " has already been registered in the wallet as own asset"); + wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id]; + asset_context.asset_descriptor = ado.descriptor; + asset_context.height = height; + std::stringstream ss; + ss << "New Asset Registered:" + << ENDL << "asset id: " << asset_id + << ENDL << "Name: " << asset_context.asset_descriptor.full_name + << ENDL << "Ticker: " << asset_context.asset_descriptor.ticker + << ENDL << "Total Max Supply: " << print_asset_money(asset_context.asset_descriptor.total_max_supply, asset_context.asset_descriptor.decimal_point) + << ENDL << "Current Supply: " << print_asset_money(asset_context.asset_descriptor.current_supply, asset_context.asset_descriptor.decimal_point) + << ENDL << "Decimal Point: " << asset_context.asset_descriptor.decimal_point; + + WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0); + if (m_wcallback) + m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + if (ado.opt_asset_id) + } + } while (false); +} + void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector* pglobal_indexes) { //check for transaction spends @@ -804,45 +852,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t asset_descriptor_operation ado = AUTO_VAL_INIT(ado); if (get_type_in_variant_container(tx.extra, ado)) { - if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) - { - crypto::public_key self_check = AUTO_VAL_INIT(self_check); - crypto::secret_key asset_control_key = AUTO_VAL_INIT(asset_control_key); - bool r = derive_key_pair_from_key_pair(tx_pub_key, m_account.get_keys().spend_secret_key, asset_control_key, self_check, CRYPTO_HDS_ASSET_CONTROL_KEY); - if (!r) - { - //not critical error, continue to work - LOG_ERROR("Failed to derive_key_pair_from_key_pair for asset_descriptor_operation in tx " << ptc.tx_hash()); - }else - { - if (self_check != ado.descriptor.owner) - { - //still not critical error - LOG_ERROR("Public key from asset_descriptor_operation(" << ado.descriptor.owner << ") not much with derived public key(" << self_check << "), for tx" << ptc.tx_hash()); - } - else - { - crypto::public_key asset_id{}; - calculate_asset_id(ado.descriptor.owner, nullptr, &asset_id); - WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_own_asset_descriptors.count(asset_id) == 0, "asset with asset_id " << asset_id << " has already been registered in the wallet as own asset"); - wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id]; - asset_context.asset_descriptor = ado.descriptor; - asset_context.height = height; - std::stringstream ss; - ss << "New Asset Registered:" - << ENDL << "asset id: " << asset_id - << ENDL << "Name: " << asset_context.asset_descriptor.full_name - << ENDL << "Ticker: " << asset_context.asset_descriptor.ticker - << ENDL << "Total Max Supply: " << print_asset_money(asset_context.asset_descriptor.total_max_supply, asset_context.asset_descriptor.decimal_point) - << ENDL << "Current Supply: " << print_asset_money(asset_context.asset_descriptor.current_supply, asset_context.asset_descriptor.decimal_point) - << ENDL << "Decimal Point: " << asset_context.asset_descriptor.decimal_point; - - WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0); - if (m_wcallback) - m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); - } - } - } + process_ado_in_new_transaction(ado); } } @@ -4636,7 +4646,7 @@ void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info ctp.extra.push_back(asset_reg_info); ctp.need_at_least_1_zc = true; - finalized_tx ft = AUTO_VAL_INIT(ft); + finalized_tx ft = AUTO_VAL_INIT(ft);6++ this->transfer(ctp, ft, true, nullptr); result_tx = ft.tx; //get generated asset id @@ -4648,16 +4658,16 @@ void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info m_custom_assets[new_asset_id] = ado.descriptor; } //---------------------------------------------------------------------------------------------------- -void wallet2::update_emmit_asset(const crypto::public_key asset_id, std::vector& destinations, currency::transaction& result_tx) +void wallet2::emmit_asset(const crypto::public_key asset_id, std::vector& destinations, currency::transaction& result_tx) { auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id); CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list"); - asset_descriptor_operation asset_reg_info = AUTO_VAL_INIT(asset_reg_info); - asset_reg_info.descriptor = asset_info; - asset_reg_info.operation_type = ASSET_DESCRIPTOR_OPERATION_EMMIT; - asset_reg_info.asset_id = asset_id; + asset_descriptor_operation asset_emmit_info = AUTO_VAL_INIT(asset_emmit_info); + asset_emmit_info.descriptor = own_asset_entry_it->second.asset_descriptor; + asset_emmit_info.operation_type = ASSET_DESCRIPTOR_OPERATION_EMMIT; + asset_emmit_info.asset_id = asset_id; construct_tx_param ctp = get_default_construct_tx_param(); ctp.dsts = destinations; ctp.extra.push_back(asset_reg_info); @@ -4667,13 +4677,6 @@ void wallet2::update_emmit_asset(const crypto::public_key asset_id, std::vector< finalized_tx ft = AUTO_VAL_INIT(ft); this->transfer(ctp, ft, true, nullptr); result_tx = ft.tx; - //get generated asset id - currency::asset_descriptor_operation ado = AUTO_VAL_INIT(ado); - bool r = get_type_in_variant_container(result_tx.extra, ado); - CHECK_AND_ASSERT_THROW_MES(r, "Failed find asset info in tx"); - calculate_asset_id(ado.descriptor.owner, nullptr, &new_asset_id); - - m_custom_assets[new_asset_id] = ado.descriptor; } //---------------------------------------------------------------------------------------------------- void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::transaction& res_tx, uint64_t fee, uint64_t reward) @@ -6544,7 +6547,7 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx const currency::transaction& tx_for_mode_separate = msc.tx_for_mode_separate; assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts); - + ftp.asset_control_key = ctp.control_key; // // TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id // diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 2df6e548..0572e03f 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1006,6 +1006,7 @@ private: void add_transfers_to_expiration_list(const std::vector& selected_transfers, const std::vector& received, uint64_t expiration, const crypto::hash& related_tx_id); void remove_transfer_from_expiration_list(uint64_t transfer_index); void load_keys(const std::string& keys_file_name, const std::string& password, uint64_t file_signature, keys_file_data& kf_data); + void process_ado_in_new_transaction(const asset_descriptor_operation& ado); void process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector* pglobal_indexes); void fetch_tx_global_indixes(const currency::transaction& tx, std::vector& goutputs_indexes); void fetch_tx_global_indixes(const std::list>& txs, std::vector>& goutputs_indexes);