diff --git a/contrib/epee/include/serialization/keyvalue_helpers.h b/contrib/epee/include/serialization/keyvalue_helpers.h index 79a4886b5..09555a9e7 100644 --- a/contrib/epee/include/serialization/keyvalue_helpers.h +++ b/contrib/epee/include/serialization/keyvalue_helpers.h @@ -85,6 +85,18 @@ namespace epee } return res; } + + // helper for blob-to-base64 serialization + inline std::string transfrom_binbuf_to_base64(const std::string& a) + { + return epee::string_encoding::base64_encode(a); + } + + inline std::string transform_base64_to_binbuf(const std::string& a) + { + return epee::string_encoding::base64_decode(a); + } + //------------------------------------------------------------------------------------------------------------------- #pragma pack(push, 1) template diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h index 31c90df7a..50f917b4b 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization.h +++ b/contrib/epee/include/serialization/keyvalue_serialization.h @@ -81,6 +81,8 @@ public: \ #define KV_SERIALIZE_BLOB_AS_HEX_STRING_N(varialble, val_name) \ KV_SERIALIZE_CUSTOM_N(varialble, std::string, epee::transform_binbuf_to_hexstr, epee::transform_hexstr_to_binbuff, val_name) +#define KV_SERIALIZE_BLOB_AS_BASE64_STRING_N(varialble, val_name) \ + KV_SERIALIZE_CUSTOM_N(varialble, std::string, epee::transfrom_binbuf_to_base64, epee::transform_base64_to_binbuf, val_name) #define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \ epee::serialization::selector::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name); @@ -100,7 +102,8 @@ public: \ #define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble) #define KV_SERIALIZE_CUSTOM(varialble, stored_type, from_v_to_stored, from_stored_to_v) KV_SERIALIZE_CUSTOM_N(varialble, stored_type, from_v_to_stored, from_stored_to_v, #varialble) #define KV_SERIALIZE_POD_AS_HEX_STRING(varialble) KV_SERIALIZE_POD_AS_HEX_STRING_N(varialble, #varialble) -#define KV_SERIALIZE_BLOB_AS_HEX_STRING(varialble) KV_SERIALIZE_BLOB_AS_HEX_STRING_N(varialble, #varialble) +#define KV_SERIALIZE_BLOB_AS_HEX_STRING(varialble) KV_SERIALIZE_BLOB_AS_HEX_STRING_N(varialble, #varialble) +#define KV_SERIALIZE_BLOB_AS_BASE64_STRING(variable) KV_SERIALIZE_BLOB_AS_BASE64_STRING_N(variable, #variable) diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index ec98bea6a..0e6c923c2 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -2548,7 +2548,7 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_ptr->out_no, false, "internal error: in global outs index, transaction out index=" << out_ptr->out_no << " is greater than transaction outputs = " << tx_ptr->tx.vout.size() << ", for tx id = " << out_ptr->tx_id); - CHECK_AND_ASSERT_MES(amount != 0 || height_upper_limit != 0, false, "height_upper_limit must be nonzero for hidden amounts (amount = 0)"); + //CHECK_AND_ASSERT_MES(amount != 0 || height_upper_limit != 0, false, "height_upper_limit must be nonzero for hidden amounts (amount = 0)"); if (height_upper_limit != 0 && tx_ptr->m_keeper_block_height > height_upper_limit) return false; @@ -2606,6 +2606,14 @@ bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPU oen.amount_commitment = toz.amount_commitment; oen.concealing_point = toz.concealing_point; oen.blinded_asset_id = toz.blinded_asset_id; // TODO @#@# bad design, too much manual coping, consider redesign -- sowle + if (is_coinbase(tx_ptr->tx)) + { + oen.flags |= RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_COINBASE; + if (is_pos_coinbase(tx_ptr->tx)) + { + oen.flags |= RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_POS_COINBASE; + } + } } VARIANT_SWITCH_END(); @@ -2694,9 +2702,9 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO return true; } //------------------------------------------------------------------ -bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const +bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const { - size_t decoys_count = details.offsets.size(); + size_t decoys_count = details.global_offsets.size(); uint64_t amount = details.amount; uint64_t outs_container_size = m_db_outputs.get_item_size(details.amount); @@ -2723,7 +2731,7 @@ bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RP if (up_index_limit >= decoys_count) { std::set used; - used.insert(details.own_global_index); + //used.insert(details.own_global_index); for (uint64_t j = 0; j != decoys_count || used.size() >= up_index_limit;) { size_t g_index_initial = crypto::rand() % up_index_limit; @@ -2766,117 +2774,27 @@ bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RP } } //------------------------------------------------------------------ -bool blockchain_storage::get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const +bool blockchain_storage::get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const { - std::set used; - used.insert(details.own_global_index); - for (auto offset : details.offsets) + for (auto global_index : details.global_offsets) { - - //perfectly we would need to find transaction's output on the given height, with the given probability - //of being coinbase(coinbase outputs should be included less in decoy selection algorithm) - bool is_coinbase = (crypto::rand() % 101) > req.coinbase_percents ? false : true; - - //TODO: Consider including PoW coinbase to transactions(does it needed?) - - // convert offset to estimated height - uint64_t estimated_h = this->get_current_blockchain_size() - 1 - offset; - //make sure it's after zc hardfork - if (estimated_h < m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]) - { - LOG_ERROR("Wrong estimated offset(" << offset << "), it hits zone before zarcanum hardfork"); - return false; - } - -#define TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN 10 - //try to find output around given H - std::vector selected_global_indexes; - auto process_tx = [&](const crypto::hash& tx_id) { - - auto tx_ptr = m_db_transactions.find(tx_id); - CHECK_AND_ASSERT_THROW_MES(tx_ptr, "internal error: tx_id " << tx_id << " around estimated_h = " << estimated_h << " not found in db"); - //go through tx outputs - for (size_t i = 0; i != tx_ptr->tx.vout.size(); i++) - { - if (tx_ptr->tx.vout[i].type() != typeid(tx_out_zarcanum)) - { - continue; - } - const tx_out_zarcanum& z_out = boost::get(tx_ptr->tx.vout[i]); - - // NOTE: second part of condition (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && ..) might be not accurate - // since the wallet might want to request more inputs then it planning to do mixins. For now let's keep it this way and fix - // it if we see the problems about it. - if (z_out.mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || (z_out.mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && z_out.mix_attr < details.offsets.size())) - { - continue; - } - - // skip spent outptus - if (tx_ptr->m_spent_flags[i]) - { - continue; - } - - if (used.find(tx_ptr->m_global_output_indexes[i]) != used.end()) - { - continue; - } - - // add output - // note: code that will process selected_global_indes will be revisiting transactions entries to obtain all - // needed data, that should work relatively effective because of on-top-of-db cache keep daya unserialized - selected_global_indexes.push_back(tx_ptr->m_global_output_indexes[i]); - } - - }; - - while (selected_global_indexes.size() < TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN) + //pick up a random output from selected_global_indes + bool res = add_out_to_get_random_outs(result_outs, details.amount, global_index, this->get_core_runtime_config().hf4_minimum_mixins, false); + if (!res) { - auto block_ptr = m_db_blocks.get(estimated_h); - if (is_coinbase && is_pos_block(block_ptr->bl) ) - { - process_tx(get_transaction_hash(block_ptr->bl.miner_tx)); - } - else - { - //looking for regular output of regular transactions - for (auto tx_id : block_ptr->bl.tx_hashes) - { - process_tx(tx_id); - } - } - if(estimated_h) - estimated_h--; - else - { - //likely unusual situation when blocks enumerated all way back to genesis - //let's check if we have at least something - if (!selected_global_indexes.size()) - { - //need to regenerate offsets - return false; - } - } + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry{}); + oen.flags = RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_NOT_ALLOWED; } - - //pick up a random output from selected_global_indes - uint64_t global_index = selected_global_indexes[crypto::rand() % selected_global_indexes.size()]; - bool res = add_out_to_get_random_outs(result_outs, details.amount, global_index, details.offsets.size(), req.use_forced_mix_outs, req.height_upper_limit); - CHECK_AND_ASSERT_THROW_MES(res, "Failed to add_out_to_get_random_outs([" << global_index << "]) at postzarcanum era"); - used.insert(global_index); } + CHECK_AND_ASSERT_THROW_MES(details.global_offsets.size() == result_outs.outs.size(), "details.global_offsets.size() == result_outs.outs.size() check failed"); return true; } //------------------------------------------------------------------ -bool blockchain_storage::get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const +bool blockchain_storage::get_random_outs_for_amounts3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res)const { CRITICAL_REGION_LOCAL(m_read_lock); LOG_PRINT_L3("[get_random_outs_for_amounts] amounts: " << req.amounts.size()); std::map amounts_to_up_index_limit_cache; - uint64_t count_zarcanum_blocks = 0; - if(is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) - count_zarcanum_blocks = this->get_current_blockchain_size() - m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]; for (size_t i = 0; i != req.amounts.size(); i++) @@ -2887,7 +2805,7 @@ bool blockchain_storage::get_random_outs_for_amounts2(const COMMAND_RPC_GET_RAND result_outs.amount = amount; bool r = false; - if (amount == 0 && count_zarcanum_blocks > 20000) + if (amount == 0) { //zarcanum era inputs r = get_target_outs_for_postzarcanum(req, req.amounts[i], result_outs, amounts_to_up_index_limit_cache); @@ -3591,7 +3509,7 @@ bool blockchain_storage::get_est_height_from_date(uint64_t date, uint64_t& res_h return true; } //------------------------------------------------------------------ -bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height, bool need_global_indexes)const +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height)const { CRITICAL_REGION_LOCAL(m_read_lock); blocks_direct_container blocks_direct; @@ -3610,7 +3528,7 @@ bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height, bool request_coinbase_info)const +bool blockchain_storage::find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height)const { CRITICAL_REGION_LOCAL(m_read_lock); if (!find_blockchain_supplement(qblock_ids, start_height)) @@ -3627,8 +3545,7 @@ bool blockchain_storage::find_blockchain_supplement(const std::list mis; get_transactions_direct(m_db_blocks[i]->bl.tx_hashes, blocks.back().second, mis); CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, block " << get_block_hash(m_db_blocks[i]->bl) << " [" << i << "] contains missing transactions: " << mis); - if(request_coinbase_info) - blocks.back().third = m_db_transactions.find(get_transaction_hash(m_db_blocks[i]->bl.miner_tx)); + blocks.back().third = m_db_transactions.find(get_transaction_hash(m_db_blocks[i]->bl.miner_tx)); } return true; } @@ -3863,6 +3780,17 @@ uint64_t blockchain_storage::get_aliases_count() const return m_db_aliases.size(); } //------------------------------------------------------------------ +bool blockchain_storage::get_asset_history(const crypto::public_key& asset_id, std::list& result) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto as_ptr = m_db_assets.find(asset_id); + if (!as_ptr) + return false; + + result = *as_ptr; + return true; +} +//------------------------------------------------------------------ bool blockchain_storage::get_asset_info(const crypto::public_key& asset_id, asset_descriptor_base& result) const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4084,7 +4012,7 @@ bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id) return true; } //------------------------------------------------------------------ -bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& avc) +bool validate_ado_ownership(asset_op_verification_context& avc) { asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop); bool r = get_type_in_variant_container(avc.tx.proofs, aoop); @@ -4096,32 +4024,23 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a return crypto::verify_schnorr_sig(avc.tx_id, owner_key, aoop.gss); } //------------------------------------------------------------------ -bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) +bool blockchain_storage::validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const { CRITICAL_REGION_LOCAL(m_read_lock); - asset_op_verification_context avc = { tx, tx_id, ado }; + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); + avc.asset_op_history = m_db_assets.find(avc.asset_id); + + const asset_descriptor_operation& ado = avc.ado; if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) { - CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); - - avc.asset_op_history = m_db_assets.find(avc.asset_id); CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << avc.asset_id << " has already been registered"); - avc.amount_to_validate = ado.descriptor.current_supply; - CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "asset operation validation failed!"); - - assets_container::t_value_type local_asset_history = AUTO_VAL_INIT(local_asset_history); - local_asset_history.push_back(ado); - m_db_assets.set(avc.asset_id, local_asset_history); - LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "validate_asset_operation_amount_commitment failed!"); } else { - CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); - avc.asset_op_history = m_db_assets.find(avc.asset_id); - CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << avc.asset_id << " has not been registered"); // check ownership permission if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE /*|| ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN*/) @@ -4164,25 +4083,40 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has bool r = validate_asset_operation_amount_commitment(avc); CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation"); } + } - assets_container::t_value_type local_asset_history = *avc.asset_op_history; - local_asset_history.push_back(ado); - m_db_assets.set(avc.asset_id, local_asset_history); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) +{ + CRITICAL_REGION_LOCAL(m_read_lock); - switch(ado.operation_type) - { - case ASSET_DESCRIPTOR_OPERATION_UPDATE: - LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - case ASSET_DESCRIPTOR_OPERATION_EMIT: - LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: - LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - default: - LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); - } + asset_op_verification_context avc = { tx, tx_id, ado }; + CHECK_AND_ASSERT_MES(validate_asset_operation_against_current_blochain_state(avc), false, "asset operation validation failed"); + + assets_container::t_value_type local_asset_history{}; + if (avc.asset_op_history) + local_asset_history = *avc.asset_op_history; + local_asset_history.push_back(ado); + m_db_assets.set(avc.asset_id, local_asset_history); + + switch(ado.operation_type) + { + case ASSET_DESCRIPTOR_OPERATION_REGISTER: + LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_UPDATE: + LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_EMIT: + LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: + LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + default: + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); } return true; @@ -5526,7 +5460,6 @@ std::shared_ptr blockchain_storage::find_key_imag //--------------------------------------------------------------- bool blockchain_storage::fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short) const { - //tei.blob = tx_ptr->tx tei.id = epee::string_tools::pod_to_hex(h); if (!tei.blob_size) tei.blob_size = get_object_blobsize(tx); @@ -5543,6 +5476,9 @@ bool blockchain_storage::fill_tx_rpc_details(tx_rpc_extended_info& tei, const tr fill_tx_rpc_outputs(tei, tx, ptce); fill_tx_rpc_payload_items(tei.extra, tx.extra); fill_tx_rpc_payload_items(tei.attachments, tx.attachment); + + tei.blob = t_serializable_object_to_blob(tx); + tei.object_in_json = obj_to_json_str(tx); return true; } //------------------------------------------------------------------ @@ -6478,11 +6414,16 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt tx.signatures.clear(); tx.proofs.clear(); } - + currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc); //std::vector tx_outs_commitments; if (!m_is_in_checkpoint_zone) { - auto cleanup = [&](){ purge_block_data_from_blockchain(bl, tx_processed_count); bvc.m_verification_failed = true; }; + auto cleanup = [&](){ + bool add_res = m_tx_pool.add_tx(tx, tvc, true, true); + m_tx_pool.add_transaction_to_black_list(tx); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + }; CHECK_AND_ASSERT_MES_CUSTOM(collect_rangeproofs_data_from_tx(tx, tx_id, range_proofs_agregated), false, cleanup(), "block " << id << ", tx " << tx_id << ": collect_rangeproofs_data_from_tx failed"); @@ -6499,7 +6440,6 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt if(!check_tx_inputs(tx, tx_id)) { LOG_PRINT_L0("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs."); - currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc); if (taken_from_pool) { bool add_res = m_tx_pool.add_tx(tx, tvc, true, true); diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 5bf57ad45..c24e1104e 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -280,13 +280,13 @@ namespace currency bool get_short_chain_history(std::list& ids)const; bool find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp)const; bool find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset)const; - bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0, bool need_global_indexes = false)const; - bool find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0, bool request_coinbase_info = false)const; + bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0)const; + bool find_blockchain_supplement(const std::list& qblock_ids, blocks_direct_container& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count, uint64_t minimum_height = 0)const; //bool find_blockchain_supplement(const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count)const; bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const; bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; - bool get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const; + bool get_random_outs_for_amounts3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res)const; bool get_backward_blocks_sizes(size_t from_height, std::vector& sz, size_t count)const; bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs)const; bool get_alias_info(const std::string& alias, extra_alias_entry_base& info)const; @@ -299,6 +299,7 @@ namespace currency uint64_t get_aliases_count()const; uint64_t get_block_h_older_then(uint64_t timestamp) const; bool validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx)const; + bool get_asset_history(const crypto::public_key& asset_id, std::list& result) const; bool get_asset_info(const crypto::public_key& asset_id, asset_descriptor_base& info)const; uint64_t get_assets_count() const; bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const; @@ -374,6 +375,8 @@ namespace currency bool for_altchain, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0)const; + bool validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const; + void set_core_runtime_config(const core_runtime_config& pc) const; const core_runtime_config& get_core_runtime_config()const; size_t get_current_sequence_factor(bool pos)const; @@ -493,6 +496,7 @@ namespace currency bool print_tx_outputs_lookup(const crypto::hash& tx_id) const; uint64_t get_last_x_block_height(bool pos)const; bool is_tx_spendtime_unlocked(uint64_t unlock_time)const; + private: //-------------- DB containers -------------- @@ -643,8 +647,8 @@ namespace currency bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false, uint64_t height_upper_limit = 0) const; - bool get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; - bool get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; + bool get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; + bool get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; bool add_block_as_invalid(const block& bl, const crypto::hash& h); bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); size_t find_end_of_allowed_index(uint64_t amount)const; @@ -669,7 +673,6 @@ namespace currency bool unprocess_blockchain_tx_extra(const transaction& tx); bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp); bool unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp); - bool validate_ado_ownership(asset_op_verification_context& avc); bool pop_alias_info(const extra_alias_entry& ai); bool put_alias_info(const transaction& tx, extra_alias_entry& ai); bool pop_asset_info(const crypto::public_key& asset_id); diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 50ca76a8c..487502f4b 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -249,13 +249,9 @@ #define BC_OFFERS_CURRENT_OFFERS_SERVICE_ARCHIVE_VER CURRENCY_FORMATION_VERSION + BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 9 #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" -#ifndef TESTNET -#define WALLET_FILE_SERIALIZATION_VERSION 163 -#define WALLET_FILE_LAST_SUPPORTED_VERSION 163 -#else -#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+76) -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+76) -#endif + +#define WALLET_FILE_SERIALIZATION_VERSION 165 +#define WALLET_FILE_LAST_SUPPORTED_VERSION 165 #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index 11d051b94..3e5a63fe2 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -134,7 +134,7 @@ namespace currency //--------------------------------------------------------------- // if cb returns true, it means "continue", false -- means "stop" template - bool process_type_in_variant_container(const variant_container_t& av, callback_t& cb, bool return_value_if_none_found = true) + bool process_type_in_variant_container(const variant_container_t& av, callback_t&& cb, bool return_value_if_none_found = true) { bool found = false; for (auto& ai : av) @@ -151,6 +151,27 @@ namespace currency return return_value_if_none_found; } //--------------------------------------------------------------- + // if cb returns false, stop immediately and return false + template + bool process_type_in_variant_container_and_make_sure_its_unique(const variant_container_t& av, callback_t&& cb, bool return_value_if_none_found = true) + { + bool found = false; + for (auto& ai : av) + { + if (ai.type() == typeid(specific_type_t)) + { + if (found) + return false; // already have it, type in not unique + found = true; + if (!cb(boost::get(ai))) + return false; + } + } + if (found) + return true; + return return_value_if_none_found; + } + //--------------------------------------------------------------- // callback should return true to continue iterating through the container template bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t cb) diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp index 3acf108c3..333158700 100644 --- a/src/currency_core/tx_pool.cpp +++ b/src/currency_core/tx_pool.cpp @@ -104,6 +104,20 @@ namespace currency //--------------------------------------------------------------------------------- bool tx_memory_pool::add_tx(const transaction &tx, const crypto::hash &id, uint64_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool from_core) { + // ------------------ UNSECURE CODE FOR TESTS --------------------- + if (m_unsecure_disable_tx_validation_on_addition) + { + uint64_t tx_fee = 0; + CHECK_AND_ASSERT_MES(get_tx_fee(tx, tx_fee), false, "get_tx_fee failed"); + do_insert_transaction(tx, id, blob_size, kept_by_block, tx_fee, null_hash, 0); + tvc.m_added_to_pool = true; + tvc.m_should_be_relayed = true; + tvc.m_verification_failed = false; + tvc.m_verification_impossible = false; + return true; + } + // ---------------- END OF UNSECURE CODE FOR TESTS ------------------- + bool r = false; // defaults @@ -224,6 +238,20 @@ namespace currency } TIME_MEASURE_FINISH_PD(check_inputs_time); + if (tx.version > TRANSACTION_VERSION_PRE_HF4) + { + TIME_MEASURE_START_PD(check_post_hf4_balance); + r = check_tx_balance(tx, id); + CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: balance proof is invalid"); + TIME_MEASURE_FINISH_PD(check_post_hf4_balance); + + r = process_type_in_variant_container_and_make_sure_its_unique(tx.extra, [&](const asset_descriptor_operation& ado){ + asset_op_verification_context avc = { tx, id, ado }; + return m_blockchain.validate_asset_operation_against_current_blochain_state(avc); + }, true); + CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: asset operation is invalid"); + } + do_insert_transaction(tx, id, blob_size, kept_by_block, tx_fee, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0); TIME_MEASURE_FINISH_PD(tx_processing_time); @@ -240,9 +268,11 @@ namespace currency << "/" << m_performance_data.validate_alias_time.get_last_val() << "/" << m_performance_data.check_keyimages_ws_ms_time.get_last_val() << "/" << m_performance_data.check_inputs_time.get_last_val() + << "/b"<< m_performance_data.check_post_hf4_balance.get_last_val() << "/" << m_performance_data.begin_tx_time.get_last_val() << "/" << m_performance_data.update_db_time.get_last_val() - << "/" << m_performance_data.db_commit_time.get_last_val() << ")" ); + << "/" << m_performance_data.db_commit_time.get_last_val() + << ")"); return true; } @@ -875,7 +905,7 @@ namespace currency { //not the best implementation at this time, sorry :( - if (m_db_black_tx_list.get(get_transaction_hash(txd.tx))) + if (is_tx_blacklisted(get_transaction_hash(txd.tx))) return false; //check is ring_signature already checked ? @@ -966,8 +996,8 @@ namespace currency return "(no transactions, the pool is empty)"; // sort output by receive time txs.sort([](const std::pair& lhs, const std::pair& rhs) -> bool { return lhs.second.receive_time < rhs.second.receive_time; }); - ss << "# | transaction id | size | fee | ins | outs | outs money | live_time | max used block | last failed block | kept by a block?" << ENDL; - // 1234 f99fe6d4335fc0ddd69e6880a4d95e0f6ea398de0324a6837021a61c6a31cacd 87157 0.10000111 2000 2000 112000.12345678 d0.h10.m16.s17 123456 <12345..> 123456 <12345..> YES + ss << "# | transaction id | size | fee | ins | outs | live_time | max used block | last failed block | ver | status " << ENDL; + // 1234 f99fe6d4335fc0ddd69e6880a4d95e0f6ea398de0324a6837021a61c6a31cacd 187157 0.10000111 2000 2000 d0.h10.m16.s17 1234567 <12345..> 1234567 <12345..> 2 kept_by_block BLACKLISTED size_t i = 0; for (auto& tx : txs) { @@ -975,17 +1005,17 @@ namespace currency ss << std::left << std::setw(4) << i++ << " " << tx.first << " " - << std::setw(5) << txd.blob_size << " " + << std::setw(6) << txd.blob_size << " " << std::setw(10) << print_money_brief(txd.fee) << " " << std::setw(4) << txd.tx.vin.size() << " " << std::setw(4) << txd.tx.vout.size() << " " - << std::right << std::setw(15) << print_money(get_outs_money_amount(txd.tx)) << std::left << " " << std::setw(14) << epee::misc_utils::get_time_interval_string(get_core_time() - txd.receive_time) << " " - << std::setw(6) << txd.max_used_block_height << " " + << std::setw(7) << txd.max_used_block_height << " " << std::setw(9) << print16(txd.max_used_block_id) << " " - << std::setw(6) << txd.last_failed_height << " " + << std::setw(7) << txd.last_failed_height << " " << std::setw(9) << print16(txd.last_failed_id) << " " - << (txd.kept_by_block ? "YES" : "no ") + << std::setw(3) << txd.tx.version << " " + << (txd.kept_by_block ? "kept_by_block " : "") << (is_tx_blacklisted(tx.first) ? "BLACKLISTED " : "") << ENDL; } return ss.str(); @@ -1314,6 +1344,11 @@ namespace currency } } //--------------------------------------------------------------------------------- + bool tx_memory_pool::is_tx_blacklisted(const crypto::hash& id) const + { + return m_db_black_tx_list.get(id) != nullptr; + } + //--------------------------------------------------------------------------------- bool tx_memory_pool::load_keyimages_cache() { CRITICAL_REGION_LOCAL(m_key_images_lock); diff --git a/src/currency_core/tx_pool.h b/src/currency_core/tx_pool.h index 92d606045..c97a498a7 100644 --- a/src/currency_core/tx_pool.h +++ b/src/currency_core/tx_pool.h @@ -77,7 +77,8 @@ namespace currency epee::math_helper::average check_inputs_time; epee::math_helper::average begin_tx_time; epee::math_helper::average update_db_time; - epee::math_helper::average db_commit_time; + epee::math_helper::average db_commit_time; + epee::math_helper::average check_post_hf4_balance; }; typedef std::unordered_map> key_image_cache; @@ -140,6 +141,12 @@ namespace currency void remove_incompatible_txs(); // made public to be called after the BCS is loaded and hardfork info is ready + bool is_tx_blacklisted(const crypto::hash& id) const; + +#ifdef TX_POOL_USE_UNSECURE_TEST_FUNCTIONS + void unsecure_disable_tx_validation_on_addition(bool validation_disabled) { m_unsecure_disable_tx_validation_on_addition = validation_disabled; } +#endif + private: bool on_tx_add(crypto::hash tx_id, const transaction& tx, bool kept_by_block); bool on_tx_remove(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block); @@ -194,6 +201,7 @@ namespace currency key_image_cache m_key_images; mutable epee::critical_section m_remove_stuck_txs_lock; + bool m_unsecure_disable_tx_validation_on_addition = false; }; } diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index 7e3955849..8f2aa24ab 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -47,6 +47,7 @@ class daemon_commands_handler m_cmd_binder.set_handler("print_block_info", boost::bind(&daemon_commands_handler::print_block_info, this, ph::_1), "Print block info, print_block | "); m_cmd_binder.set_handler("print_tx_prun_info", boost::bind(&daemon_commands_handler::print_tx_prun_info, this, ph::_1), "Print tx prunning info"); m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_commands_handler::print_tx, this, ph::_1), "Print transaction, print_tx "); + m_cmd_binder.set_handler("print_asset_info", boost::bind(&daemon_commands_handler::print_asset_info, this, ph::_1), "Print information about the given asset by its id"); m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_commands_handler::start_mining, this, ph::_1), "Start mining for specified address, start_mining [threads=1]"); m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_commands_handler::stop_mining, this, ph::_1), "Stop mining"); m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_commands_handler::print_pool, this, ph::_1), "Print transaction pool (long format)"); @@ -688,7 +689,7 @@ class daemon_commands_handler { if (args.empty()) { - std::cout << "expected: print_tx " << std::endl; + std::cout << "usage: print_tx " << std::endl; return true; } @@ -696,55 +697,74 @@ class daemon_commands_handler crypto::hash tx_hash; if (!parse_hash256(str_hash, tx_hash)) { + LOG_PRINT_RED_L0("invalid tx hash was given"); return true; } - // std::vector tx_ids; - // tx_ids.push_back(tx_hash); - // std::list txs; - // std::list missed_ids; - // m_srv.get_payload_object().get_core().get_transactions(tx_ids, txs, missed_ids); - - currency::transaction_chain_entry tx_entry = AUTO_VAL_INIT(tx_entry); - - if (!m_srv.get_payload_object().get_core().get_blockchain_storage().get_tx_chain_entry(tx_hash, tx_entry)) + currency::tx_rpc_extended_info tx_rpc_ei{}; + currency::core& core = m_srv.get_payload_object().get_core(); + if (core.get_blockchain_storage().get_tx_rpc_details(tx_hash, tx_rpc_ei, 0, false)) { - LOG_PRINT_RED("transaction wasn't found: " << tx_hash, LOG_LEVEL_0); + // pass + } + else if (core.get_tx_pool().get_transaction_details(tx_hash, tx_rpc_ei)) + { + // pass + } + else + { + LOG_PRINT_RED("transaction " << tx_hash << " was not found in either the blockchain or the pool", LOG_LEVEL_0); + return true; } - currency::block_extended_info bei = AUTO_VAL_INIT(bei); - m_srv.get_payload_object().get_core().get_blockchain_storage().get_block_extended_info_by_height(tx_entry.m_keeper_block_height, bei); - uint64_t timestamp = bei.bl.timestamp; - const currency::transaction& tx = tx_entry.tx; std::stringstream ss; + ss << ENDL << + "----------------------TX-HEX--------------------------" << ENDL << + epee::string_tools::buff_to_hex_nodelimer(tx_rpc_ei.blob) << ENDL << + "------------------END-OF-TX-HEX-----------------------" << ENDL; - ss << "------------------------------------------------------" - << ENDL << "tx_id: " << tx_hash - << ENDL << "keeper_block: " << tx_entry.m_keeper_block_height << ", timestamp (" << timestamp << ") " << epee::misc_utils::get_internet_time_str(timestamp) - << ENDL << currency::obj_to_json_str(tx) - << ENDL << "------------------------------------------------------" - << ENDL << epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx)) - << ENDL << "------------------------------------------------------"; + ss << ENDL << + "tx " << tx_hash << " "; + if (tx_rpc_ei.keeper_block == -1) + { + ss << "has been in the transaction pool for " << epee::misc_utils::get_time_interval_string(core.get_blockchain_storage().get_core_runtime_config().get_core_time() - tx_rpc_ei.timestamp) << + ", added " << epee::misc_utils::get_internet_time_str(tx_rpc_ei.timestamp) << ", ts: " << tx_rpc_ei.timestamp << ", blob size: " << tx_rpc_ei.blob_size << ENDL; + } + else + { + ss << "was added to block @ " << tx_rpc_ei.keeper_block << ", block time: " << epee::misc_utils::get_internet_time_str(tx_rpc_ei.timestamp) << ", ts: " << tx_rpc_ei.timestamp << ", blob size: " << tx_rpc_ei.blob_size << ENDL; + } - ss << "ATTACHMENTS: " << ENDL; - for (auto at : tx.attachment) + ss << ENDL << + "-----------------------JSON---------------------------" << ENDL << + tx_rpc_ei.object_in_json << ENDL << + "--------------------END-OF-JSON-----------------------" << ENDL; + + currency::transaction tx{}; + CHECK_AND_ASSERT_MES(currency::parse_and_validate_tx_from_blob(tx_rpc_ei.blob, tx), true, "parse_and_validate_tx_from_blob failed"); + + if (!tx.attachment.empty()) { - if (at.type() == typeid(currency::tx_service_attachment)) + ss << "ATTACHMENTS: " << ENDL; + for (auto at : tx.attachment) { - const currency::tx_service_attachment& sa = boost::get(at); - ss << "++++++++++++++++++++++++++++++++ " << ENDL; - ss << "[SERVICE_ATTACHMENT]: ID = \'" << sa.service_id << "\', INSTRUCTION: \'" << sa.instruction << "\'" << ENDL; - - if (!(sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY)) + if (at.type() == typeid(currency::tx_service_attachment)) { - std::string body = sa.body; - if (sa.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + const currency::tx_service_attachment& sa = boost::get(at); + ss << "++++++++++++++++++++++++++++++++ " << ENDL; + ss << "[SERVICE_ATTACHMENT]: ID = \'" << sa.service_id << "\', INSTRUCTION: \'" << sa.instruction << "\'" << ENDL; + + if (!(sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY)) { - bool r = epee::zlib_helper::unpack(sa.body, body); - CHECK_AND_ASSERT_MES(r, false, "Failed to unpack"); + std::string body = sa.body; + if (sa.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + { + bool r = epee::zlib_helper::unpack(sa.body, body); + CHECK_AND_ASSERT_MES(r, false, "Failed to unpack"); + } + ss << "BODY: " << body << ENDL; } - ss << "BODY: " << body << ENDL; } } } @@ -753,6 +773,56 @@ class daemon_commands_handler return true; } //-------------------------------------------------------------------------------- + bool print_asset_info(const std::vector& args) + { + if (args.empty()) + { + std::cout << "usage: print_asset_info " << std::endl; + return true; + } + + const std::string& str_asset_id = args.front(); + crypto::public_key asset_id{}; + crypto::point_t asset_id_pt{}; + if (!crypto::parse_tpod_from_hex_string(str_asset_id, asset_id) || !asset_id_pt.from_public_key(asset_id)) + { + LOG_PRINT_RED_L0("invalid asset id was given"); + return true; + } + + currency::core& core = m_srv.get_payload_object().get_core(); + + std::list asset_history; + if (!core.get_blockchain_storage().get_asset_history(asset_id, asset_history)) + { + LOG_PRINT_RED_L0("asset id doesn't present in the blockchain"); + return true; + } + + std::stringstream ss; + ss << ENDL << + "history for asset " << asset_id << ":" << ENDL; + + size_t idx = 0; + for(auto& aop: asset_history) + { + ss << "[" << std::setw(2) << idx << "] operation: " << currency::get_asset_operation_type_string(aop.operation_type) << " (" << (int)aop.operation_type << ")" << ENDL << + " ticker: \"" << aop.descriptor.ticker << "\"" << ENDL << + " full name: \"" << aop.descriptor.full_name << "\"" << ENDL << + " meta info: \"" << aop.descriptor.meta_info << "\"" << ENDL << + " current supply: " << currency::print_money_brief(aop.descriptor.current_supply, aop.descriptor.decimal_point) << ENDL << + " max supply: " << currency::print_money_brief(aop.descriptor.total_max_supply, aop.descriptor.decimal_point) << ENDL << + " decimal point: " << (int)aop.descriptor.decimal_point << ENDL << + " owner * 1/8: " << aop.descriptor.owner << ENDL << + " amount cmt * 1/8: " << aop.amount_commitment << ENDL << + " hidden supply: " << (aop.descriptor.hidden_supply ? "yes" : "no") << ENDL << + ""; + } + + LOG_PRINT_L0(ss.str()); + return true; + } + //-------------------------------------------------------------------------------- bool print_tx_outputs_usage(const std::vector& args) { if (args.empty()) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 7eda942c0..cd9c20d28 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -289,7 +289,7 @@ namespace currency } blockchain_storage::blocks_direct_container bs; - if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height, req.need_global_indexes)) + if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height)) { res.status = API_RETURN_CODE_FAIL; return false; @@ -326,7 +326,7 @@ namespace currency } blockchain_storage::blocks_direct_container bs; - if (!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height, req.need_global_indexes)) + if (!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, bs, res.current_height, res.start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT, req.minimum_height)) { res.status = API_RETURN_CODE_FAIL; return false; @@ -336,21 +336,15 @@ namespace currency { res.blocks.resize(res.blocks.size()+1); res.blocks.back().block = block_to_blob(b.first->bl); - if (req.need_global_indexes) - { - CHECK_AND_ASSERT_MES(b.third.get(), false, "Internal error on handling COMMAND_RPC_GET_BLOCKS_FAST: b.third is empty, ie coinbase info is not prepared"); - res.blocks.back().coinbase_global_outs = b.third->m_global_output_indexes; - res.blocks.back().tx_global_outs.resize(b.second.size()); - } + CHECK_AND_ASSERT_MES(b.third.get(), false, "Internal error on handling COMMAND_RPC_GET_BLOCKS_FAST: b.third is empty, ie coinbase info is not prepared"); + res.blocks.back().coinbase_global_outs = b.third->m_global_output_indexes; + res.blocks.back().tx_global_outs.resize(b.second.size()); size_t i = 0; BOOST_FOREACH(auto& t, b.second) { res.blocks.back().txs.push_back(tx_to_blob(t->tx)); - if (req.need_global_indexes) - { - res.blocks.back().tx_global_outs[i].v = t->m_global_output_indexes; - } + res.blocks.back().tx_global_outs[i].v = t->m_global_output_indexes; i++; } } @@ -424,11 +418,11 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx) + bool core_rpc_server::on_get_random_outs3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res, connection_context& cntx) { CHECK_CORE_READY(); res.status = API_RETURN_CODE_FAIL; - if (!m_core.get_blockchain_storage().get_random_outs_for_amounts2(req, res)) + if (!m_core.get_blockchain_storage().get_random_outs_for_amounts3(req, res)) { return true; } @@ -989,7 +983,7 @@ namespace currency res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height)); res.status = API_RETURN_CODE_OK; - + LOG_PRINT_L1("COMMAND_RPC_GETBLOCKTEMPLATE OK, response block: " << ENDL << currency::obj_to_json_str(resp.b)); return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -1339,6 +1333,20 @@ namespace currency res.status = API_RETURN_CODE_OK; return true; } + + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_remove_tx_from_pool(const COMMAND_RPC_REMOVE_TX_FROM_POOL::request& req, COMMAND_RPC_REMOVE_TX_FROM_POOL::response& res, connection_context& cntx) + { + for (const auto& tx_id_str : req.tx_to_remove) + { + crypto::hash tx_id = epee::transform_str_to_t_pod(tx_id_str); + currency::transaction tx; size_t dummy1 = 0; uint64_t dummy2 = 0; + m_core.get_tx_pool().take_tx(tx_id, tx, dummy1, dummy2); + } + + res.status = API_RETURN_CODE_OK; + return true; + } } diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 2c7b47a9c..daf9452c7 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -50,7 +50,7 @@ namespace currency bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx); bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_LEGACY::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_LEGACY::response& res, connection_context& cntx); bool on_get_random_outs1(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx); - bool on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx); + bool on_get_random_outs3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res, connection_context& cntx); bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx); bool on_set_maintainers_info(const COMMAND_RPC_SET_MAINTAINERS_INFO::request& req, COMMAND_RPC_SET_MAINTAINERS_INFO::response& res, connection_context& cntx); bool on_get_tx_pool(const COMMAND_RPC_GET_TX_POOL::request& req, COMMAND_RPC_GET_TX_POOL::response& res, connection_context& cntx); @@ -75,6 +75,7 @@ namespace currency bool on_aliases_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_alias_reward(const COMMAND_RPC_GET_ALIAS_REWARD::request& req, COMMAND_RPC_GET_ALIAS_REWARD::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_reset_transaction_pool(const COMMAND_RPC_RESET_TX_POOL::request& req, COMMAND_RPC_RESET_TX_POOL::response& res, connection_context& cntx); + bool on_remove_tx_from_pool(const COMMAND_RPC_REMOVE_TX_FROM_POOL::request& req, COMMAND_RPC_REMOVE_TX_FROM_POOL::response& res, connection_context& cntx); bool on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx); bool on_get_current_core_tx_expiration_median(const COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res, connection_context& cntx); bool on_get_tx_details(const COMMAND_RPC_GET_TX_DETAILS::request& req, COMMAND_RPC_GET_TX_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); @@ -112,7 +113,7 @@ namespace currency MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES) MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_LEGACY) MAP_URI_AUTO_BIN2("/getrandom_outs1.bin", on_get_random_outs1, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) - MAP_URI_AUTO_BIN2("/getrandom_outs2.bin", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2) + MAP_URI_AUTO_BIN2("/getrandom_outs3.bin", on_get_random_outs3, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3) MAP_URI_AUTO_BIN2("/set_maintainers_info.bin", on_set_maintainers_info, COMMAND_RPC_SET_MAINTAINERS_INFO) MAP_URI_AUTO_BIN2("/get_tx_pool.bin", on_get_tx_pool, COMMAND_RPC_GET_TX_POOL) MAP_URI_AUTO_BIN2("/check_keyimages.bin", on_check_keyimages, COMMAND_RPC_CHECK_KEYIMAGES) @@ -146,7 +147,7 @@ namespace currency MAP_JON_RPC ("get_pool_info", on_get_pool_info, COMMAND_RPC_GET_POOL_INFO) MAP_JON_RPC ("getrandom_outs", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS_LEGACY) MAP_JON_RPC ("getrandom_outs1", on_get_random_outs1, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) - MAP_JON_RPC ("getrandom_outs2", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2) + MAP_JON_RPC ("getrandom_outs3", on_get_random_outs3, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3) MAP_JON_RPC ("get_votes", on_get_votes, COMMAND_RPC_GET_VOTES) //assets api MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO) @@ -156,6 +157,7 @@ namespace currency MAP_JON_RPC ("get_alt_blocks_details", on_get_alt_blocks_details, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS) // MAP_JON_RPC ("reset_transaction_pool", on_reset_transaction_pool, COMMAND_RPC_RESET_TX_POOL) + MAP_JON_RPC ("remove_tx_from_pool", on_remove_tx_from_pool, COMMAND_RPC_REMOVE_TX_FROM_POOL) MAP_JON_RPC ("get_current_core_tx_expiration_median", on_get_current_core_tx_expiration_median, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN) // MAP_JON_RPC_WE("marketplace_global_get_offers_ex", on_get_offers_ex, COMMAND_RPC_GET_OFFERS_EX) diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index ca55f2d4f..42648bfa8 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -161,12 +161,10 @@ namespace currency struct request { - bool need_global_indexes; uint64_t minimum_height; std::list block_ids; //*first 10 blocks id goes sequential, next goes in pow(2,n) offset, like 2, 4, 8, 16, 32, 64 and so on, and the last one is always genesis block */ BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(need_global_indexes) KV_SERIALIZE(minimum_height) KV_SERIALIZE_CONTAINER_POD_AS_BLOB(block_ids) END_KV_SERIALIZE_MAP() @@ -382,6 +380,11 @@ namespace currency END_KV_SERIALIZE_MAP() }; + +#define RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_COINBASE 0x0000000000000001LL +#define RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_NOT_ALLOWED 0x0000000000000002LL +#define RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_POS_COINBASE 0x0000000000000004LL + #pragma pack (push, 1) struct out_entry { @@ -397,12 +400,13 @@ namespace currency crypto::public_key concealing_point; // premultiplied by 1/8 crypto::public_key amount_commitment; // premultiplied by 1/8 crypto::public_key blinded_asset_id; // premultiplied by 1/8 + uint64_t flags; }; #pragma pack(pop) struct outs_for_amount { - uint64_t amount; + uint64_t amount = 0; std::list outs; BEGIN_KV_SERIALIZE_MAP() @@ -422,18 +426,16 @@ namespace currency }; }; //----------------------------------------------- - struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2 + struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3 { struct offsets_distribution { uint64_t amount; //if amount is 0 then lookup in post-zarcanum zone only, if not 0 then pre-zarcanum only - std::vector offsets; //[i] = height, estimated location where to pickup output of transaction - uint64_t own_global_index; //index to exclude from selection + std::vector global_offsets; //[i] = global_index to pick up BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) - KV_SERIALIZE(offsets) - KV_SERIALIZE(own_global_index) + KV_SERIALIZE(global_offsets) END_KV_SERIALIZE_MAP() }; @@ -1248,6 +1250,28 @@ namespace currency }; }; + struct COMMAND_RPC_REMOVE_TX_FROM_POOL + { + + struct request + { + std::list tx_to_remove; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_to_remove) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_GET_POS_MINING_DETAILS { struct request @@ -1342,7 +1366,7 @@ namespace currency std::string object_in_json; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(blob) + KV_SERIALIZE_BLOB_AS_BASE64_STRING(blob) KV_SERIALIZE(blob_size) KV_SERIALIZE(timestamp) KV_SERIALIZE(keeper_block) @@ -1354,7 +1378,7 @@ namespace currency KV_SERIALIZE(ins) KV_SERIALIZE(extra) KV_SERIALIZE(attachments) - KV_SERIALIZE(object_in_json) + KV_SERIALIZE_BLOB_AS_BASE64_STRING(object_in_json) END_KV_SERIALIZE_MAP() }; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 1a1f1e8e0..ed51ef76b 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -2113,11 +2113,11 @@ bool simple_wallet::emit_asset(const std::vector &args) tx_destination_entry td = AUTO_VAL_INIT(td); td.addr.push_back(m_wallet->get_account().get_public_address()); td.amount = amount; - td.asset_id = asset_id; + td.asset_id = currency::null_pkey; std::vector destinations; destinations.push_back(td); currency::transaction result_tx = AUTO_VAL_INIT(result_tx); - m_wallet->emmit_asset(asset_id, destinations, result_tx); + m_wallet->emit_asset(asset_id, destinations, result_tx); success_msg_writer(true) << "Emitted " << get_transaction_hash(result_tx) << " (unconfirmed) : " << ENDL << "Asset ID: " << asset_id << ENDL diff --git a/src/version.h.in b/src/version.h.in index 2f3a2265f..fc6d8a54e 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "0" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 284 +#define PROJECT_VERSION_BUILD_NO 290 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" diff --git a/src/wallet/core_default_rpc_proxy.cpp b/src/wallet/core_default_rpc_proxy.cpp index 92cf11bcf..0836cb75a 100644 --- a/src/wallet/core_default_rpc_proxy.cpp +++ b/src/wallet/core_default_rpc_proxy.cpp @@ -39,7 +39,6 @@ namespace tools currency::COMMAND_RPC_GET_BLOCKS_FAST::request req; req.block_ids = rqt.block_ids; req.minimum_height = rqt.minimum_height; - req.need_global_indexes = rqt.need_global_indexes; currency::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res); bool r = call_COMMAND_RPC_GET_BLOCKS_FAST(req, res); rsp.status = res.status; @@ -77,9 +76,9 @@ namespace tools return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs1.bin", req, res); } //------------------------------------------------------------------------------------------------------------------------------ - bool default_http_core_proxy::call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res) + bool default_http_core_proxy::call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res) { - return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs2.bin", req, res); + return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs3.bin", req, res); } //------------------------------------------------------------------------------------------------------------------------------ bool default_http_core_proxy::call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& req, currency::COMMAND_RPC_SEND_RAW_TX::response& res) diff --git a/src/wallet/core_default_rpc_proxy.h b/src/wallet/core_default_rpc_proxy.h index 2d28c0710..b27cbbcf5 100644 --- a/src/wallet/core_default_rpc_proxy.h +++ b/src/wallet/core_default_rpc_proxy.h @@ -37,7 +37,7 @@ namespace tools bool call_COMMAND_RPC_GET_TX_POOL(const currency::COMMAND_RPC_GET_TX_POOL::request& rqt, currency::COMMAND_RPC_GET_TX_POOL::response& rsp) override; bool call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(const currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& rqt, currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& rsp) override; bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& rsp) override; - bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& rsp) override; + bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& rsp) override; bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& rqt, currency::COMMAND_RPC_SEND_RAW_TX::response& rsp) override; bool call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(const currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& rqt, currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& rsp) override; bool call_COMMAND_RPC_GET_ALL_ALIASES(currency::COMMAND_RPC_GET_ALL_ALIASES::response& rsp) override; diff --git a/src/wallet/core_fast_rpc_proxy.h b/src/wallet/core_fast_rpc_proxy.h index 3d212676d..d96ee86f8 100644 --- a/src/wallet/core_fast_rpc_proxy.h +++ b/src/wallet/core_fast_rpc_proxy.h @@ -58,9 +58,9 @@ namespace tools return m_rpc.on_get_random_outs1(req, res, m_cntxt_stub); } //------------------------------------------------------------------------------------------------------------------------------ - bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res) override + bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res) override { - return m_rpc.on_get_random_outs2(req, res, m_cntxt_stub); + return m_rpc.on_get_random_outs3(req, res, m_cntxt_stub); } //------------------------------------------------------------------------------------------------------------------------------ bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& req, currency::COMMAND_RPC_SEND_RAW_TX::response& res) override diff --git a/src/wallet/core_rpc_proxy.h b/src/wallet/core_rpc_proxy.h index effec3405..1ab16633a 100644 --- a/src/wallet/core_rpc_proxy.h +++ b/src/wallet/core_rpc_proxy.h @@ -36,7 +36,7 @@ namespace tools virtual bool call_COMMAND_RPC_GET_TX_POOL(const currency::COMMAND_RPC_GET_TX_POOL::request& rqt, currency::COMMAND_RPC_GET_TX_POOL::response& rsp){ return false; } virtual bool call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(const currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& rqt, currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& rsp){ return false; } virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& rsp){ return false; } - virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& rsp) { return false; } + virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& rsp) { return false; } virtual bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& rqt, currency::COMMAND_RPC_SEND_RAW_TX::response& rsp){ return false; } virtual bool call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(const currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& rqt, currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& rsp){ return false; } virtual bool call_COMMAND_RPC_GET_ALL_ALIASES(currency::COMMAND_RPC_GET_ALL_ALIASES::response& rsp){ return false; } diff --git a/src/wallet/decoy_selection.cpp b/src/wallet/decoy_selection.cpp index a75f333d6..7a3c8d010 100644 --- a/src/wallet/decoy_selection.cpp +++ b/src/wallet/decoy_selection.cpp @@ -24,9 +24,10 @@ uint64_t scaler::scale(uint64_t h) void decoy_selection_generator::init(uint64_t max_h) { + load_distribution(g_default_distribution, max_h); m_is_initialized = true; - + m_max = max_h; // distribution INCLUDE m_max, count = m_max + 1 } bool decoy_selection_generator::load_distribution_from_file(const char* path) { @@ -66,6 +67,60 @@ std::vector decoy_selection_generator::generate_distribution(uint64_t return res; } + +std::vector decoy_selection_generator::generate_unique_reversed_distribution(uint64_t count) +{ + std::set set_to_extend; + generate_unique_reversed_distribution(count, set_to_extend); + return std::vector(set_to_extend.begin(), set_to_extend.end()); +} + +std::vector decoy_selection_generator::generate_unique_reversed_distribution(uint64_t count, uint64_t preincluded_item) +{ + std::set set_to_extend; + set_to_extend.insert(preincluded_item); + generate_unique_reversed_distribution(count, set_to_extend); + return std::vector(set_to_extend.begin(), set_to_extend.end()); +} + +#define DECOY_SELECTION_GENERATOR_MAX_ITERATIONS 1000000 + +void decoy_selection_generator::generate_unique_reversed_distribution(uint64_t count, std::set& set_to_extend) +{ + if (count + set_to_extend.size() > m_max) + { + throw std::runtime_error("generate_distribution_set with unexpected count"); + } + + size_t attempt_count = 0; + while (set_to_extend.size() != count) + { + attempt_count++; + if (attempt_count > DECOY_SELECTION_GENERATOR_MAX_ITERATIONS) + { + throw std::runtime_error("generate_distribution_set: attempt_count hit DECOY_SELECTION_GENERATOR_MAX_ITERATIONS"); + } + + uint64_t r = 0; + crypto::generate_random_bytes(sizeof(r), &r); + double r_ = map_uint_to_double(r); + auto it = m_distribution_mapping.upper_bound(r_); + if (it == m_distribution_mapping.end()) + { + throw(std::runtime_error(std::string("_r not found in m_distribution_mapping: ") + std::to_string(r_))); + } + uint64_t h = it->second; + if (it != m_distribution_mapping.begin()) + { + uint64_t h_0 = (--it)->second; + crypto::generate_random_bytes(sizeof(r), &r); + h = h_0 + r % (h - h_0) + 1; + } + //scale from nominal to max_h + set_to_extend.insert(m_max - h); + } +} + uint64_t get_distance(const std::vector entries, size_t i) { if (i == 0) @@ -79,7 +134,8 @@ bool decoy_selection_generator::load_distribution(const std::vector derived_distribution; scaler scl; - scl.config_scale(original_distribution.back().h, max_h); + uint64_t adjustment_value = original_distribution[0].h; + scl.config_scale(original_distribution.back().h - adjustment_value, max_h); uint64_t last_scaled_h = 0; std::list last_scaled_array; @@ -87,7 +143,7 @@ bool decoy_selection_generator::load_distribution(const std::vector generate_distribution(uint64_t count); + std::vector generate_unique_reversed_distribution(uint64_t count, uint64_t preincluded_item); + std::vector generate_unique_reversed_distribution(uint64_t count); + void generate_unique_reversed_distribution(uint64_t count, std::set& set_to_extend); bool is_initialized() { return m_is_initialized; } private: bool load_distribution(const std::vector& entries, uint64_t max_h); bool m_is_initialized = false; + uint64_t m_max = 0; std::map m_distribution_mapping; }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 23ff25968..1264781e9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -62,6 +62,10 @@ using namespace currency; #define WALLET_TX_MAX_ALLOWED_FEE (COIN * 100) +#define WALLET_FETCH_RANDOM_OUTS_SIZE 200 + + + #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "wallet" ENABLE_CHANNEL_BY_DEFAULT("wallet") @@ -77,9 +81,11 @@ namespace tools , m_log_prefix("???") , m_watch_only(false) , m_required_decoys_count(CURRENCY_DEFAULT_DECOY_SET_SIZE) + , m_defragmentation_tx_enabled(false) + , m_max_allowed_output_amount_for_defragmentation_tx(CURRENCY_BLOCK_REWARD) , m_min_utxo_count_for_defragmentation_tx(WALLET_MIN_UTXO_COUNT_FOR_DEFRAGMENTATION_TX) , m_max_utxo_count_for_defragmentation_tx(WALLET_MAX_UTXO_COUNT_FOR_DEFRAGMENTATION_TX) - , m_decoys_count_for_defragmentation_tx(WALLET_DEFAULT_DECOYS_COUNT_FOR_DEFRAGMENTATION_TX) + , m_decoys_count_for_defragmentation_tx(SIZE_MAX) , m_use_deffered_global_outputs(false) #ifdef DISABLE_TOR , m_disable_tor_relay(true) @@ -526,8 +532,18 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t //PoW block don't have change, so all outs supposed to be marked as "mined" ptc.is_derived_from_coinbase = !ptc.is_pos_coinbase; ptc.height = height; - - + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pglobal_indexes, "pglobal_indexes not set"); + if (this->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)) + { + if (pglobal_indexes->size()) + { + //store global index that is under coinage, so we can used in decoy selection algo + if (ptc.height < m_last_known_daemon_height && m_last_known_daemon_height - ptc.height > WALLET_DEFAULT_TX_SPENDABLE_AGE) + { + m_last_zc_global_index = pglobal_indexes->back(); + } + } + } for(auto& in : tx.vin) { @@ -1917,8 +1933,6 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop) currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response res = AUTO_VAL_INIT(res); req.minimum_height = get_wallet_minimum_height(); - if (is_auditable()) - req.need_global_indexes = true; if (req.minimum_height > m_height_of_start_sync) m_height_of_start_sync = req.minimum_height; @@ -1971,12 +1985,14 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& res) { size_t current_index = res.start_height; + m_last_known_daemon_height = res.current_height; bool been_matched_block = false; if (res.start_height == 0 && get_blockchain_current_size() == 1 && !res.blocks.empty()) { const currency::block& genesis = res.blocks.front().block_ptr->bl; THROW_IF_TRUE_WALLET_EX(get_block_height(genesis) != 0, error::wallet_internal_error, "first block expected to be genesis"); - process_genesis_if_needed(genesis); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(res.blocks.front().coinbase_ptr, "Unexpected empty coinbase"); + process_genesis_if_needed(genesis, &(res.blocks.front().coinbase_ptr->m_global_output_indexes)); res.blocks.pop_front(); ++current_index; been_matched_block = true; @@ -3661,6 +3677,9 @@ void wallet2::get_transfers(transfer_container& incoming_transfers) const //---------------------------------------------------------------------------------------------------- bool wallet2::generate_utxo_defragmentation_transaction_if_needed(currency::transaction& tx) { + if (!m_defragmentation_tx_enabled) + return false; + construct_tx_param ctp = get_default_construct_tx_param(); ctp.create_utxo_defragmentation_tx = true; finalized_tx ftp{}; @@ -4939,7 +4958,7 @@ void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info m_custom_assets[new_asset_id] = ado.descriptor; } //---------------------------------------------------------------------------------------------------- -void wallet2::emmit_asset(const crypto::public_key asset_id, std::vector& destinations, currency::transaction& result_tx) +void wallet2::emit_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); @@ -4961,6 +4980,12 @@ void wallet2::emmit_asset(const crypto::public_key asset_id, std::vectorsecond.control_key; + for(auto& dst : ctp.dsts) + { + if (dst.asset_id == asset_id) + dst.asset_id = null_pkey; // emit operation requires null_pkey for emitting asset outputs, fix it ad-hoc here + } + finalized_tx ft = AUTO_VAL_INIT(ft); this->transfer(ctp, ft, true, nullptr); result_tx = ft.tx; @@ -5926,8 +5951,8 @@ bool wallet2::decrypt_buffer(const std::string& buff, std::string& res_buff) //---------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources_for_defragmentation_tx(std::vector& sources, std::vector& selected_indicies, uint64_t& found_money) { - //prepare_free_transfers_cache(fake_outputs_count); - //free_amounts_cache_type& free_amounts_for_native_coin = m_found_free_amounts[currency::native_coin_asset_id]; + if (!m_defragmentation_tx_enabled) + return false; std::stringstream ss; if (epee::log_space::log_singletone::get_log_detalisation_level() >= LOG_LEVEL_2) @@ -5935,10 +5960,11 @@ bool wallet2::prepare_tx_sources_for_defragmentation_tx(std::vector CURRENCY_BLOCK_REWARD) + if (!td.is_native_coin() || td.m_amount > m_max_allowed_output_amount_for_defragmentation_tx) continue; - if (is_transfer_ready_to_go(td, m_decoys_count_for_defragmentation_tx)) + uint64_t fake_outs_count_for_td = m_decoys_count_for_defragmentation_tx == SIZE_MAX ? (td.is_zc() ? m_core_runtime_config.hf4_minimum_mixins : CURRENCY_DEFAULT_DECOY_SET_SIZE) : m_decoys_count_for_defragmentation_tx; + if (is_transfer_ready_to_go(td, fake_outs_count_for_td)) { found_money += td.m_amount; selected_indicies.push_back(i); @@ -5947,7 +5973,7 @@ bool wallet2::prepare_tx_sources_for_defragmentation_tx(std::vector& sources, std::vector& selected_indicies) @@ -5970,17 +5996,18 @@ bool wallet2::prepare_tx_sources(assets_selection_context& needed_money_map, siz //---------------------------------------------------------------------------------------------------- void wallet2::prefetch_global_indicies_if_needed(const std::vector& selected_indicies) { - std::list> txs; - std::list indices_that_requested_global_indicies; + //std::list> txs; + //std::list indices_that_requested_global_indicies; for (uint64_t i : selected_indicies) { - if (m_transfers[i].m_global_output_index == WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED) - { - indices_that_requested_global_indicies.push_back(i); - txs.push_back(m_transfers[i].m_ptx_wallet_info->m_tx); - } + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers[i].m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, + "m_transfers[" << i << "].m_global_output_index is WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED"); + //indices_that_requested_global_indicies.push_back(i); + //txs.push_back(m_transfers[i].m_ptx_wallet_info->m_tx); + //} } + /* std::vector > outputs_for_all_txs; fetch_tx_global_indixes(txs, outputs_for_all_txs); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(txs.size() == outputs_for_all_txs.size(), "missmatch sizes txs.size() == outputs_for_all_txs.size()"); @@ -5991,7 +6018,7 @@ void wallet2::prefetch_global_indicies_if_needed(const std::vector& se transfer_details& td = m_transfers[*it_indices]; td.m_global_output_index = (*it_ooutputs)[td.m_internal_output_index]; it_ooutputs++; it_indices++; - } + }*/ } //---------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector& sources, const std::vector& selected_indicies) @@ -6011,26 +6038,26 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector= zarcanum_start_from) { //in Zarcanum era - const uint64_t test_scale_size = current_size - 1 - zarcanum_start_from; - zarcanum_decoy_set_generator.init(test_scale_size - 1); + //const uint64_t test_scale_size = current_size - 1 - zarcanum_start_from; + zarcanum_decoy_set_generator.init(m_last_zc_global_index); } bool need_to_request = fake_outputs_count != 0; - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request req = AUTO_VAL_INIT(req); + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request req = AUTO_VAL_INIT(req); req.height_upper_limit = m_last_pow_block_h; // request decoys to be either older than, or the same age as stake output's height req.use_forced_mix_outs = false; // TODO: add this feature to UI later //req.decoys_count = fake_outputs_count + 1; // one more to be able to skip a decoy in case it hits the real output for (uint64_t i: selected_indicies) { - req.amounts.push_back(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution()); - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& rdisttib = req.amounts.back(); + req.amounts.push_back(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution()); + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& rdisttib = req.amounts.back(); auto it = m_transfers.begin() + i; WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->m_ptx_wallet_info->m_tx.vout.size() > it->m_internal_output_index, "m_internal_output_index = " << it->m_internal_output_index << " is greater or equal to outputs count = " << it->m_ptx_wallet_info->m_tx.vout.size()); - rdisttib.own_global_index = it->m_global_output_index; + //rdisttib.own_global_index = it->m_global_output_index; //check if we have Zarcanum era output of pre-Zarcanum if (it->is_zc()) { @@ -6039,15 +6066,14 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vectorm_global_output_index); need_to_request = true; } else { //for prezarcanum era use flat distribution rdisttib.amount = it->m_amount; - rdisttib.offsets.resize(fake_outputs_count, 0); + rdisttib.global_offsets.resize(fake_outputs_count + 1, 0); } } if (need_to_request) @@ -6056,8 +6082,8 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vectorcall_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(req, daemon_resp); - THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs2.bin"); + bool r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3(req, daemon_resp); + THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs3.bin"); if (daemon_resp.status == API_RETURN_CODE_FAIL) { if (attempt_count < 10) @@ -6080,10 +6106,9 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector scanty_outs; THROW_IF_FALSE_WALLET_EX(daemon_resp.outs.size() == req.amounts.size(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count); - //for (COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs : daemon_resp.outs) for(size_t i = 0; i != daemon_resp.outs.size(); i++) { - if (daemon_resp.outs[i].outs.size() != req.amounts[i].offsets.size()) + if (req.amounts[i].amount != 0 && daemon_resp.outs[i].outs.size() != req.amounts[i].global_offsets.size()) { scanty_outs.push_back(daemon_resp.outs[i]); } @@ -6093,6 +6118,7 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector= fake_outputs_count) break; @@ -6188,6 +6224,72 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector +typename t_obj_container::value_type extract_random_from_container(t_obj_container& container) +{ + auto it = container.begin(); + std::advance(it, (crypto::rand() % container.size())); + typename t_obj_container::value_type obj = *it; + container.erase(it); + return obj; +} +//---------------------------------------------------------------------------------------------------------------- +void wallet2::select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_entry, uint64_t own_g_index) +{ + THROW_IF_FALSE_WALLET_INT_ERR_EX(amount_entry.amount == 0, "Amount is not 0 in zc decoys entry"); + typedef currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; + + //TODO: This strategy would be a subject for continuous refactoring + + //first take all real transactions if ther are some + std::list local_outs; + std::list coinbases; + + while (amount_entry.outs.size() && local_outs.size() != m_core_runtime_config.hf4_minimum_mixins) + { + out_entry entry = extract_random_from_container(amount_entry.outs); + + //skip auditable + if ((entry.flags & (RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_NOT_ALLOWED))) + { + continue; + } + if (entry.flags & (RANDOM_OUTPUTS_FOR_AMOUNTS_FLAGS_COINBASE)) + { + coinbases.push_back(entry); + continue; + } + // + if (entry.global_amount_index == own_g_index) + { + continue; + } + + local_outs.push_back(entry); + } + + //extend with coin base outs if needed + while (coinbases.size() && local_outs.size() != m_core_runtime_config.hf4_minimum_mixins) + { + out_entry entry = extract_random_from_container(coinbases); + local_outs.push_back(entry); + } + + THROW_IF_FALSE_WALLET_INT_ERR_EX(local_outs.size() == m_core_runtime_config.hf4_minimum_mixins, "Amount is not 0 in zc decoys entry"); + amount_entry.outs = local_outs; +} +//---------------------------------------------------------------------------------------------------------------- +void wallet2::build_distribution_for_input(decoy_selection_generator& zarcanum_decoy_set_generator, std::vector& offsets, uint64_t own_index) +{ + THROW_IF_FALSE_WALLET_INT_ERR_EX(zarcanum_decoy_set_generator.is_initialized(), "zarcanum_decoy_set_generator are not initialized"); + if (m_core_runtime_config.hf4_minimum_mixins) + { + offsets = zarcanum_decoy_set_generator.generate_unique_reversed_distribution(m_last_zc_global_index - 1 > WALLET_FETCH_RANDOM_OUTS_SIZE ? WALLET_FETCH_RANDOM_OUTS_SIZE: m_last_zc_global_index - 1, own_index); + } +} //---------------------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources(crypto::hash multisig_id, std::vector& sources, uint64_t& found_money) { @@ -6719,7 +6821,7 @@ bool wallet2::prepare_free_transfers_cache(uint64_t fake_outputs_count) if (td.m_zc_info_ptr) { //zarcanum out, redefine fake_outputs_count - fake_outputs_count_local = this->is_auditable() ? 0 : CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE; + fake_outputs_count_local = this->is_auditable() ? 0 : m_core_runtime_config.hf4_minimum_mixins; } if (is_transfer_able_to_go(td, fake_outputs_count_local)) { @@ -6824,7 +6926,7 @@ bool wallet2::is_connected_to_net() return (res.synchronized_connections_count) ? true : false; } //---------------------------------------------------------------------------------------------------- -void wallet2::process_genesis_if_needed(const currency::block& genesis) +void wallet2::process_genesis_if_needed(const currency::block& genesis, const std::vector* pglobal_indexes) { if (!m_transfers.empty() || !m_key_images.empty()) return; @@ -6842,7 +6944,7 @@ void wallet2::process_genesis_if_needed(const currency::block& genesis) m_last_bc_timestamp = genesis.timestamp; WLT_LOG_L2("Processing genesis block: " << genesis_hash); - process_new_transaction(genesis.miner_tx, 0, genesis, nullptr); + process_new_transaction(genesis.miner_tx, 0, genesis, pglobal_indexes); } //---------------------------------------------------------------------------------------------------- void wallet2::set_genesis(const crypto::hash& genesis_hash) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 74df897c0..05863a185 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -46,6 +46,7 @@ #include "currency_core/pos_mining.h" #include "view_iface.h" #include "wallet2_base.h" +#include "decoy_selection.h" #define WALLET_DEFAULT_TX_SPENDABLE_AGE CURRENCY_HF4_MANDATORY_MIN_COINAGE #define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1 @@ -147,6 +148,9 @@ namespace tools std::unordered_map m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key uint64_t m_last_pow_block_h = 0; std::list> m_rollback_events; + uint64_t m_last_zc_global_index = 0; + + //variables that not being serialized std::atomic m_last_bc_timestamp = 0; @@ -218,6 +222,7 @@ namespace tools a & m_rollback_events; a & m_whitelisted_assets; a & m_use_assets_whitelisting; + a & m_last_zc_global_index; } }; @@ -389,7 +394,7 @@ namespace tools bool check_available_sources(std::list& amounts); void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id); - void emmit_asset(const crypto::public_key asset_id, std::vector& destinations, currency::transaction& result_tx); + void emit_asset(const crypto::public_key asset_id, std::vector& destinations, currency::transaction& result_tx); void update_asset(const crypto::public_key asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx); void burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx); void transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx); @@ -754,7 +759,7 @@ namespace tools bool scan_not_compliant_unconfirmed_txs(); const currency::transaction& get_transaction_by_id(const crypto::hash& tx_hash); void rise_on_transfer2(const wallet_public::wallet_transfer_info& wti); - void process_genesis_if_needed(const currency::block& genesis); + void process_genesis_if_needed(const currency::block& genesis, const std::vector* pglobal_indexes); bool build_escrow_proposal(bc_services::contract_private_details& ecrow_details, uint64_t fee, uint64_t unlock_time, currency::tx_service_attachment& att, std::vector& selected_indicies); bool prepare_tx_sources(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust_threshold, std::vector& sources, std::vector& selected_indicies); bool prepare_tx_sources(size_t fake_outputs_count, std::vector& sources, const std::vector& selected_indicies); @@ -850,6 +855,8 @@ namespace tools void remove_transfer_from_amount_gindex_map(uint64_t tid); uint64_t get_alias_cost(const std::string& alias); detail::split_strategy_id_t get_current_split_strategy(); + void build_distribution_for_input(decoy_selection_generator& zarcanum_decoy_set_generator, std::vector& offsets, uint64_t own_index); + void select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount & amount_entry, uint64_t own_g_index); static void wti_to_csv_entry(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); static void wti_to_txt_line(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index); @@ -877,9 +884,13 @@ namespace tools bool m_do_rise_transfer; + + bool m_defragmentation_tx_enabled; + uint64_t m_max_allowed_output_amount_for_defragmentation_tx; uint64_t m_min_utxo_count_for_defragmentation_tx; uint64_t m_max_utxo_count_for_defragmentation_tx; size_t m_decoys_count_for_defragmentation_tx; + size_t m_required_decoys_count; pending_ki_file_container_t m_pending_key_images_file_container; uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value @@ -903,6 +914,8 @@ namespace tools std::string m_votes_config_path; tools::wallet_public::wallet_vote_config m_votes_config; + uint64_t m_last_known_daemon_height = 0; + //this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions friend class test_generator; }; // class wallet2 diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index a602ecba7..516329ff2 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -25,25 +25,25 @@ using namespace epee; catch (const tools::error::daemon_busy& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; \ - er.message = e.what(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY") + e.what(); \ return false; \ } \ catch (const tools::error::not_enough_money& e) \ { \ - er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = e.error_code(); \ + er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY; \ + er.message = std::string("WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY") + e.error_code(); \ return false; \ } \ catch (const tools::error::wallet_error& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = e.error_code(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR") + e.error_code(); \ return false; \ } \ catch (const std::exception& e) \ { \ er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \ - er.message = e.what(); \ + er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR") + e.what(); \ return false; \ } \ catch (...) \ diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h index f9c0a2a00..d24302e03 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -13,3 +13,4 @@ #define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4 #define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5 #define WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT -6 +#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -7 diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index c1edabff1..d41ccca18 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -48,7 +48,7 @@ #define TX_POOL_SCAN_INTERVAL 1 #endif -#define HTTP_PROXY_TIMEOUT 2000 +#define HTTP_PROXY_TIMEOUT 4000 #define HTTP_PROXY_ATTEMPTS_COUNT 1 const command_line::arg_descriptor arg_alloc_win_console ( "alloc-win-console", "Allocates debug console with GUI", false ); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 71b544c1f..323dbbd81 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,11 +29,11 @@ add_executable(net_load_tests_srv net_load_tests/srv.cpp) add_dependencies(coretests version) target_link_libraries(coretests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) -target_link_libraries(functional_tests rpc wallet currency_core crypto common zlibstatic ethash libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(functional_tests rpc wallet currency_core crypto common zlibstatic ethash libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(hash-tests crypto ethash) target_link_libraries(hash-target-tests crypto currency_core ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(performance_tests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(unit_tests wallet currency_core common crypto gtest_main zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(performance_tests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) +target_link_libraries(unit_tests wallet currency_core common crypto gtest_main zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(net_load_tests_clt currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(net_load_tests_srv currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index f03bf1a28..73340589e 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1,11 +1,9 @@ -// Copyright (c) 2014-2022 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on pseudorandom number generator manupulations for tests - #include "chaingen.h" #include @@ -553,12 +551,16 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain, //skip genesis currency::block_direct_data_entry bdde = AUTO_VAL_INIT(bdde); std::shared_ptr bptr(new block_extended_info()); - bptr->bl = b->b; + bptr->bl = b->b; bdde.block_ptr = bptr; + std::shared_ptr coinbase_tx_ptr(new transaction_chain_entry()); + coinbase_tx_ptr->m_global_output_indexes = get_tx_gindex_from_map(currency::get_transaction_hash(b->b.miner_tx), txs_outs); + bdde.coinbase_ptr = coinbase_tx_ptr; for (auto& tx : b->m_transactions) { std::shared_ptr tx_ptr(new transaction_chain_entry()); tx_ptr->tx = tx; + tx_ptr->m_global_output_indexes = get_tx_gindex_from_map(currency::get_transaction_hash(tx), txs_outs); bdde.txs_ptr.push_back(tx_ptr); } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 690bdef5f..087e0c3a4 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2022 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -9,7 +9,8 @@ #include #include -#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on pseudorandom number generator manupulations for tests +#define USE_INSECURE_RANDOM_RPNG_ROUTINES // turns on pseudorandom number generator manupulations for tests +#define TX_POOL_USE_UNSECURE_TEST_FUNCTIONS // turns on special tests functions of tx pool #include "currency_core/currency_basic.h" #include "currency_core/currency_core.h" @@ -752,6 +753,17 @@ bool shuffle_source_entries(std::vector& sources); // one output will be created for each destination entry and one additional output to add up to old coinbase total amount bool replace_coinbase_in_genesis_block(const std::vector& destinations, test_generator& generator, std::vector& events, currency::block& genesis_block); +template +const std::vector& get_tx_gindex_from_map(const crypto::hash& tx_id, const t_map& id_to_vector) +{ + auto it_global_indexes = id_to_vector.find(tx_id); + if (it_global_indexes == id_to_vector.end()) + { + throw std::runtime_error("TX ID NOT FOUND"); + } + return it_global_indexes->second; +} + //-------------------------------------------------------------------------- template auto do_check_tx_verification_context(const currency::tx_verification_context& tvc, bool tx_added, size_t event_index, const currency::transaction& tx, t_test_class& validator, int) @@ -994,6 +1006,7 @@ namespace crypto { } } + inline uint64_t get_sources_total_amount(const std::vector& s) { uint64_t result = 0; diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 31d317f76..aa0974a44 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1089,6 +1089,8 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4"); GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki); GENERATE_AND_PLAY(wallet_sending_to_integrated_address); + GENERATE_AND_PLAY_HF(block_template_blacklist_test, "4-*"); + // GENERATE_AND_PLAY(emission_test); // simulate 1 year of blockchain, too long run (1 y ~= 1 hr), by demand only // LOG_ERROR2("print_reward_change_first_blocks.log", currency::print_reward_change_first_blocks(525601).str()); // outputs first 1 year of blocks' rewards (simplier) diff --git a/tests/core_tests/hard_fork_4.cpp b/tests/core_tests/hard_fork_4.cpp index 2c4a7fd32..e5b4d6b45 100644 --- a/tests/core_tests/hard_fork_4.cpp +++ b/tests/core_tests/hard_fork_4.cpp @@ -89,6 +89,10 @@ bool hard_fork_4_consolidated_txs::generate(std::vector& event ADD_CUSTOM_EVENT(events, tx_0b); MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list({tx_0a, tx_0b})); + size_t dhc = count_type_in_variant_container(tx_0b.extra); + CHECK_AND_ASSERT_MES(dhc == tx_0b.vout.size(), false, "unexpected derivation hints count: " << dhc); + + REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // check Alice's balance @@ -100,7 +104,7 @@ bool hard_fork_4_consolidated_txs::generate(std::vector& event CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice", alice_amount, 0, alice_amount, 0, 0), false, ""); uint64_t miner_amount = MK_TEST_COINS(60); - uint64_t bob_amount = miner_amount + alice_amount - TX_DEFAULT_FEE; + m_bob_amount = miner_amount + alice_amount - TX_DEFAULT_FEE; // Consolidated tx (TX_FLAG_SIGNATURE_MODE_SEPARATE). @@ -119,17 +123,33 @@ bool hard_fork_4_consolidated_txs::generate(std::vector& event std::vector destinations; if (miner_change != 0) destinations.push_back(tx_destination_entry(miner_change, miner_acc.get_public_address())); - destinations.push_back(tx_destination_entry(bob_amount, bob_acc.get_public_address())); + destinations.push_back(tx_destination_entry(m_bob_amount, bob_acc.get_public_address())); add_flags_to_all_destination_entries(tx_destination_entry_flags::tdef_explicit_native_asset_id, destinations); r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, get_tx_version_from_events(events), one_time_secret_key, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, TX_DEFAULT_FEE, gen_context); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + dhc = count_type_in_variant_container(tx_1.extra); + CHECK_AND_ASSERT_MES(dhc == destinations.size(), false, "unexpected derivation hints count: " << dhc); + // partially completed tx_1 shouldn't be accepted - //DO_CALLBACK(events, "mark_invalid_tx"); - ADD_CUSTOM_EVENT(events, tx_1); - MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_1); + + // now we added a balance check to tx_memory_pool::add_tx() for post-HF4 txs, so the behaviour is the same -- partially completed consolidated tx won't be added to the pool -- sowle + // (subject to change in future) + + //if (m_post_hf4_zarcanum) + //{ + // ADD_CUSTOM_EVENT(events, tx_1); + // DO_CALLBACK(events, "mark_invalid_block"); + // MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_1); + // DO_CALLBACK(events, "clear_tx_pool"); + //} + //else + //{ + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + //} } @@ -147,23 +167,25 @@ bool hard_fork_4_consolidated_txs::generate(std::vector& event 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, 0 /* note zero fee here */, gen_context); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + size_t dhc_2 = count_type_in_variant_container(tx_1.extra); + CHECK_AND_ASSERT_MES(dhc_2 == dhc, false, "unexpected derivation hints count: " << dhc_2); + ADD_CUSTOM_EVENT(events, tx_1); } MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1); - //std::shared_ptr bob_wlt; - //r = generator.init_test_wallet(bob_acc, get_block_hash(blk_0), bob_wlt); - //CHECK_AND_ASSERT_MES(r, false, "init_test_wallet failed"); - //r = generator.refresh_test_wallet(events, bob_wlt.get(), get_block_hash(blk_2), 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2); - //CHECK_AND_ASSERT_MES(r, false, "refresh_test_wallet failed"); - //CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", bob_amount, 0, 0, 0, 0), false, ""); - + DO_CALLBACK(events, "c1"); return true; } bool hard_fork_4_consolidated_txs::c1(currency::core& c, size_t ev_index, const std::vector& events) { + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX); + bob_wlt->refresh(); + + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", m_bob_amount, 0, 0, 0, 0), false, ""); + return true; } diff --git a/tests/core_tests/hard_fork_4.h b/tests/core_tests/hard_fork_4.h index bf12419f0..f82356756 100644 --- a/tests/core_tests/hard_fork_4.h +++ b/tests/core_tests/hard_fork_4.h @@ -13,6 +13,7 @@ struct hard_fork_4_consolidated_txs : public wallet_test bool c1(currency::core& c, size_t ev_index, const std::vector& events); mutable bool m_post_hf4_zarcanum = false; + mutable uint64_t m_bob_amount = 0; }; diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index 28dda0e5d..240b3bb3b 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -142,9 +142,9 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v CHECK_AND_ASSERT_MES(asset_info2.meta_info == asset_info.meta_info, false, "Failed to find needed asset in result balances"); - //test emmit function + //test emit function //use same destinations as we used before - miner_wlt->emmit_asset(asset_id, destinations, tx); + miner_wlt->emit_asset(asset_id, destinations, tx); r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); @@ -186,7 +186,20 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info"); asset_info.meta_info = "{\"some2\": \"info2\"}"; + r = false; + try + { + miner_wlt->update_asset(asset_id, asset_info, tx); + } + catch(tools::error::tx_rejected&) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "Test failed, broken ownership passed"); + + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(true); miner_wlt->update_asset(asset_id, asset_info, tx); + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(false); r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 2); CHECK_AND_ASSERT_MES(!r, false, "Test failed, broken ownership passed"); c.get_tx_pool().purge_transactions(); @@ -202,25 +215,54 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info"); asset_info.ticker = "XXX"; + r = false; + try + { + miner_wlt->update_asset(asset_id, asset_info, tx); + } + catch(tools::error::tx_rejected&) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "update_asset succeeded, but this shouldn't happened"); + + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(true); miner_wlt->update_asset(asset_id, asset_info, tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(false); c.get_tx_pool().purge_transactions(); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not added + // check update_asset() with modified 'full_name' r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info); CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info"); asset_info.full_name = "XXX"; + r = false; + try + { + miner_wlt->update_asset(asset_id, asset_info, tx); + } + catch(tools::error::tx_rejected&) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "update_asset succeeded, but this shouldn't happened"); + + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(true); miner_wlt->update_asset(asset_id, asset_info, tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(false); c.get_tx_pool().purge_transactions(); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not added miner_wlt->refresh(); @@ -229,13 +271,27 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info"); asset_info.decimal_point = 3; + r = false; + try + { + miner_wlt->update_asset(asset_id, asset_info, tx); + } + catch(tools::error::tx_rejected&) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "update_asset succeeded, but this shouldn't happened"); + + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(true); miner_wlt->update_asset(asset_id, asset_info, tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(false); c.get_tx_pool().purge_transactions(); miner_wlt->refresh(); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not added // check update_asset() with modified 'owner' @@ -252,20 +308,35 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v //miner_wlt->refresh(); - // check emmit_asset() with modified 'current_supply' + // check emit_asset() with modified 'current_supply' miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT([&](const wde_construct_tx_handle_asset_descriptor_operation_before_seal& o) { o.pado->descriptor.current_supply += 1000000; }); - //test emmit function but re-adjust current_supply to wrong amount - miner_wlt->emmit_asset(asset_id, destinations, tx); + //test emit function but re-adjust current_supply to wrong amount + r = false; + try + { + miner_wlt->emit_asset(asset_id, destinations, tx); + } + catch(tools::error::tx_rejected&) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "emit_asset succeeded, but this shouldn't happened"); + + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(true); + miner_wlt->emit_asset(asset_id, destinations, tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(false); c.get_tx_pool().purge_transactions(); miner_wlt->refresh(); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not added + //------------------- tests that trying to break stuff ------------------- //test burn that burns more than tx has miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL(); @@ -276,11 +347,24 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v }); + r = false; + try + { + miner_wlt->burn_asset(asset_id, 10000000000000, tx); + } + catch(tools::error::tx_rejected&) + { + r = true; + } + CHECK_AND_ASSERT_MES(r, false, "burn_asset succeeded, but this shouldn't happened"); + + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(true); miner_wlt->burn_asset(asset_id, 10000000000000, tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed + c.get_tx_pool().unsecure_disable_tx_validation_on_addition(false); c.get_tx_pool().purge_transactions(); miner_wlt->refresh(); miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL(); @@ -305,7 +389,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v uint64_t balance_alice_asset = alice_wlt->balance(asset_id); uint64_t balance_miner_asset = miner_wlt->balance(asset_id); - alice_wlt->emmit_asset(asset_id, destinations, tx); + alice_wlt->emit_asset(asset_id, destinations, tx); r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); @@ -315,7 +399,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == balance_miner_asset + destinations[0].amount, false, "Miner balance wrong"); CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == balance_alice_asset + destinations[1].amount, false, "Alice balance wrong"); - //TODO: attempt to emmmit from old key, attempt to emmit from more then max supply + //TODO: attempt to emmmit from old key, attempt to emit from more then max supply return true; } diff --git a/tests/core_tests/wallet_test_core_proxy.cpp b/tests/core_tests/wallet_test_core_proxy.cpp index e303bc8c1..db0fd0fcb 100644 --- a/tests/core_tests/wallet_test_core_proxy.cpp +++ b/tests/core_tests/wallet_test_core_proxy.cpp @@ -99,20 +99,30 @@ bool wallet_test_core_proxy::call_COMMAND_RPC_GET_BLOCKS_FAST(const currency::CO { auto b = m_blocks[i]; currency::block_complete_entry bce = AUTO_VAL_INIT(bce); - for (auto tx : b->m_transactions) + bce.tx_global_outs.resize(b->m_transactions.size()); + bce.coinbase_global_outs = get_tx_gindex(currency::get_transaction_hash(b->b.miner_tx)); + for (size_t j = 0; j != b->m_transactions.size(); j++) + { + const auto& tx = b->m_transactions[j]; bce.txs.push_back(tx_to_blob(tx)); + bce.tx_global_outs[j].v = get_tx_gindex(currency::get_transaction_hash(tx)); + } bce.block = block_to_blob(b->b); rsp.blocks.push_back(bce); } rsp.current_height = m_blocks.size(); return true; } + +const std::vector& wallet_test_core_proxy::get_tx_gindex(const crypto::hash& tx_id) +{ + return get_tx_gindex_from_map(tx_id, m_txs_outs); +} bool wallet_test_core_proxy::call_COMMAND_RPC_GET_BLOCKS_DIRECT(const currency::COMMAND_RPC_GET_BLOCKS_DIRECT::request& rqt, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& rsp) { currency::COMMAND_RPC_GET_BLOCKS_FAST::request req = AUTO_VAL_INIT(req); req.block_ids = rqt.block_ids; req.minimum_height = rqt.minimum_height; - req.need_global_indexes = rqt.need_global_indexes; currency::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res); bool r = this->call_COMMAND_RPC_GET_BLOCKS_FAST(req, res); rsp.status = res.status; diff --git a/tests/core_tests/wallet_test_core_proxy.h b/tests/core_tests/wallet_test_core_proxy.h index 322a7bb31..052a4f706 100644 --- a/tests/core_tests/wallet_test_core_proxy.h +++ b/tests/core_tests/wallet_test_core_proxy.h @@ -26,6 +26,9 @@ struct wallet_test_core_proxy : public tools::i_core_proxy virtual bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res) override; virtual bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override; + const std::vector& get_tx_gindex(const crypto::hash& tx_id); + + test_generator::tx_global_indexes m_txs_outs; test_generator::blockchain_vector m_blocks; test_generator::outputs_index m_oi; diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 373ac3a0c..0be2a9bd4 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -3809,3 +3809,95 @@ bool wallet_and_sweep_below::c1(currency::core& c, size_t ev_index, const std::v return true; } + + +//------------------------------------------------------------------------------ +block_template_blacklist_test::block_template_blacklist_test() +{ + REGISTER_CALLBACK_METHOD(block_template_blacklist_test, c1); +} + +bool block_template_blacklist_test::generate(std::vector& events) const +{ + // Test idea: basic check for wallet2::sweep_below() functionality + + uint64_t ts = test_core_time::get_time(); + m_accounts.resize(TOTAL_ACCS_COUNT); + account_base preminer_acc; + preminer_acc.generate(); + preminer_acc.set_createtime(ts); + account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts); + account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts); + MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, ts); + DO_CALLBACK(events, "configure_core"); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, preminer_acc); + + REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, 3 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1); + + DO_CALLBACK(events, "c1"); + return true; +} + +bool block_template_blacklist_test::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false; + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + + miner_wlt->refresh(); + miner_wlt->transfer(COIN / 10, alice_wlt->get_account().get_public_address()); + miner_wlt->transfer(COIN / 10, alice_wlt->get_account().get_public_address()); + + //take first transaction and corrupt it intentionalyy + std::list txs; + c.get_tx_pool().get_transactions(txs); + CHECK_AND_ASSERT_MES(txs.size() == 2, false, "wrong tx count"); + + + txs.resize(1); + currency::transaction broken_tx; + uint64_t blob_size = 0; + uint64_t fee = 0; + r = c.get_tx_pool().take_tx(currency::get_transaction_hash(*txs.begin()), broken_tx, blob_size, fee); + CHECK_AND_ASSERT_MES(r, false, "failed to take from pool"); + + + broken_tx.signatures.resize(broken_tx.signatures.size() - 1); + //manually add completely broken tx to pool + c.get_tx_pool().do_insert_transaction(broken_tx, get_transaction_hash(broken_tx), currency::get_object_blobsize(broken_tx), false, get_tx_fee(broken_tx), c.get_block_id_by_height(0), 0); + + CHECK_AND_ASSERT_MES(c.get_tx_pool().get_transactions_count() == 2, false, "wrong tx count"); + + + currency::create_block_template_params cbtp = AUTO_VAL_INIT(cbtp); + cbtp.miner_address = miner_wlt->get_account().get_public_address(); + + { + currency::create_block_template_response cbtr = AUTO_VAL_INIT(cbtr); + r = c.get_block_template(cbtp, cbtr); + + CHECK_AND_ASSERT_MES(r, false, "failed to create block template"); + CHECK_AND_ASSERT_MES(cbtr.b.tx_hashes.size() == 2, false, "failed to create block template"); + } + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(!r, false, "Unexpectedly created block"); + + //now let's check if broken tx actually added to next blocktemplate + + { + currency::create_block_template_response cbtr = AUTO_VAL_INIT(cbtr); + r = c.get_block_template(cbtp, cbtr); + + CHECK_AND_ASSERT_MES(r, false, "failed to create block template"); + CHECK_AND_ASSERT_MES(cbtr.b.tx_hashes.size() == 1, false, "failed to create block template"); + + } + + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "Unexpectedly failed to create block"); + + + return true; +} diff --git a/tests/core_tests/wallet_tests.h b/tests/core_tests/wallet_tests.h index a5aad4487..cad3871e0 100644 --- a/tests/core_tests/wallet_tests.h +++ b/tests/core_tests/wallet_tests.h @@ -294,3 +294,11 @@ struct wallet_and_sweep_below : public wallet_test bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + + +struct block_template_blacklist_test : public wallet_test +{ + block_template_blacklist_test(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; \ No newline at end of file diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index acd1f4066..e84f17d31 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -27,12 +27,18 @@ #include "wallet/plain_wallet_api.h" #include "wallet/view_iface.h" + void test_plain_wallet() { - std::string res = plain_wallet::init("195.201.107.230", "33336", "E:\\tmp\\", 0); + //std::string res = plain_wallet::init("195.201.107.230", "33336", "E:\\tmp\\", 0); + std::string res = plain_wallet::init("127.0.0.1", "12111", "C:\\Users\\roky\\home\\", 0); uint64_t instance_id = 0; - res = plain_wallet::open("test.zan", "111"); + res = plain_wallet::open("test_restored.zan", "111"); + //res = plain_wallet::restore("heart level clear fate sorrow childhood sent fate ceiling party third steel came ask mix neither message already almost vast date glide tumble color okay space", + // "test_restored.zan", "111", ""); + + while(true) { epee::misc_utils::sleep_no_w(2000); @@ -44,9 +50,23 @@ void test_plain_wallet() } - std::string invoke_body = "{\"method\":\"get_recent_txs_and_info\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}"; - - res = plain_wallet::sync_call("invoke", instance_id, invoke_body); + std::string invoke_body = "{\"method\":\"store\",\"params\":{}}"; + //std::string res1 = plain_wallet::sync_call("invoke", instance_id, invoke_body); + + invoke_body = "{\"method\":\"get_recent_txs_and_info\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}"; + std::string res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body); + + invoke_body = "{\"method\":\"getbalance\",\"params\":{}}"; + std::string res3 = plain_wallet::sync_call("invoke", instance_id, invoke_body); + + + invoke_body = "{\"method\":\"getbalance\",\"params\":{}}"; + std::string res4 = plain_wallet::sync_call("invoke", instance_id, invoke_body); + + + invoke_body = "{\r\n \"method\": \"transfer\",\r\n \"params\": {\r\n \"destinations\": [\r\n {\r\n \"amount\": \"1000000000000\",\r\n \"address\": \"ZxD9oVwGwW6ULix9Pqttnr7JDpaoLvDVA1KJ9eA9KRxPMRZT5X7WwtU94XH1Z6q6XTMxNbHmbV2xfZ429XxV6fST2DxEg4BQV\" }\r\n ],\r\n \"fee\": 10000000000,\r\n \"mixin\": 10,\r\n \"payment_id\": \"\",\r\n \"comment\": \"\",\r\n \"push_payer\": false,\r\n \"hide_receiver\": true\r\n }\r\n}"; + std::string res5 = plain_wallet::sync_call("invoke", instance_id, invoke_body); + LOG_PRINT_L0(res); } @@ -56,10 +76,10 @@ int main(int argc, char** argv) { epee::string_tools::set_module_name_and_folder(argv[0]); epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2); - epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2); - epee::log_space::log_singletone::add_logger(LOGGER_FILE, - epee::log_space::log_singletone::get_default_log_file().c_str(), - epee::log_space::log_singletone::get_default_log_folder().c_str()); + //epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2); + //epee::log_space::log_singletone::add_logger(LOGGER_FILE, + // epee::log_space::log_singletone::get_default_log_file().c_str(), + // epee::log_space::log_singletone::get_default_log_folder().c_str()); test_plain_wallet(); //parse_weird_tx(); diff --git a/tests/performance_tests/single_tx_test_base.h b/tests/performance_tests/single_tx_test_base.h index 9bda38091..a605d624f 100644 --- a/tests/performance_tests/single_tx_test_base.h +++ b/tests/performance_tests/single_tx_test_base.h @@ -18,9 +18,10 @@ class single_tx_test_base m_bob.generate(); uint64_t block_reward_without_fee = 0; - if (!construct_miner_tx(0, 0, 0, 2, 0, m_bob.get_keys().account_address, m_bob.get_keys().account_address, m_tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4, blobdata(), CURRENCY_MINER_TX_MAX_OUTS)) - return false; + uint64_t block_reward = 0; + if(!construct_miner_tx(0, 0, 0, 2, 0, m_bob.get_keys().account_address, m_bob.get_keys().account_address, m_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, blobdata(), CURRENCY_MINER_TX_MAX_OUTS)) + return false; m_tx_pub_key = get_tx_pub_key_from_extra(m_tx); return true; } diff --git a/tests/unit_tests/decoy_selection.cpp b/tests/unit_tests/decoy_selection.cpp index 47ff298d3..19c2d1780 100644 --- a/tests/unit_tests/decoy_selection.cpp +++ b/tests/unit_tests/decoy_selection.cpp @@ -10,32 +10,39 @@ TEST(decoy_selection_test, decoy_selection_test) { const uint64_t test_scale_size = 20000; decoy_selection_generator dsg; - dsg.init(test_scale_size - 1); + dsg.init(100); std::map hits; + + + + //std::vector decoys = dsg.generate_distribution(15); + + std::cout << ""; + //std::vector hits(test_scale_size, 0); -// while (true) -// { -// std::vector decoys = dsg.generate_distribution(15); -// for (auto d : decoys) -// { -// hits[d]++; -// } -// -// if (hits[10] > 500) -// break; -// -// } -// std::stringstream ss; -// for (auto it = hits.begin(); it != hits.end(); it++) -// { -// //if (hits[i] != 0) -// { -// ss << it->first << ", " << it->second << ENDL; -// } -// } -// epee::file_io_utils::save_string_to_file("distribution.csv", ss.str()); + while (true) + { + std::vector decoys = dsg.generate_distribution(15); + for (auto d : decoys) + { + hits[d]++; + } + + if (hits[10] > 500) + break; + + } + std::stringstream ss; + for (auto it = hits.begin(); it != hits.end(); it++) + { + if (it->second != 0) + { + ss << it->first << ", " << it->second << std::endl; + } + } + epee::file_io_utils::save_string_to_file("distribution.csv", ss.str()); diff --git a/utils/test_api_files/get_alias_by_address.json b/utils/test_api_files/get_alias_by_address.json new file mode 100644 index 000000000..c89f7e97c --- /dev/null +++ b/utils/test_api_files/get_alias_by_address.json @@ -0,0 +1 @@ +{"method": "get_alias_details","params": {"alias": "zoidb"}} \ No newline at end of file diff --git a/utils/test_api_files/get_alias_details.json b/utils/test_api_files/get_alias_details.json index c89f7e97c..27871aa7b 100644 --- a/utils/test_api_files/get_alias_details.json +++ b/utils/test_api_files/get_alias_details.json @@ -1 +1 @@ -{"method": "get_alias_details","params": {"alias": "zoidb"}} \ No newline at end of file +{"method": "get_alias_details","params": "ZxCjF84feY7GQZ1fdy9r3ZJABwaFjmb2Dd25H5qANWZ2VufpmyNu7ZnShMBDpiw8VW2k1EjPZswgFZnx3v1EYgJ32Rjn64mq9"} \ No newline at end of file