From d7c67b196caf0f1010419a96d1fb26f84b4e2b33 Mon Sep 17 00:00:00 2001 From: cryptozoidberg Date: Thu, 28 Nov 2019 05:28:36 +0100 Subject: [PATCH] added explicit transactions to blocktemplate --- src/currency_core/currency_core.cpp | 5 ++ src/currency_core/currency_core.h | 3 +- .../currency_format_utils_transactions.h | 2 + src/currency_core/miner.h | 1 + src/rpc/core_rpc_server.cpp | 43 +++++++++----- src/rpc/core_rpc_server_commands_defs.h | 3 +- src/wallet/wallet2.cpp | 58 +++++++++++++++++-- src/wallet/wallet2.h | 11 +++- 8 files changed, 104 insertions(+), 22 deletions(-) diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 032c19ee..ceb88406 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -333,6 +333,11 @@ namespace currency return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe); } //----------------------------------------------------------------------------------------------- + bool core::get_block_template(const create_block_template_params& params, create_block_template_response& resp) + { + return m_blockchain_storage.create_block_template(params, resp); + } + //----------------------------------------------------------------------------------------------- bool core::find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const { return m_blockchain_storage.find_blockchain_supplement(qblock_ids, resp); diff --git a/src/currency_core/currency_core.h b/src/currency_core/currency_core.h index cdadf317..faeec262 100644 --- a/src/currency_core/currency_core.h +++ b/src/currency_core/currency_core.h @@ -53,7 +53,8 @@ namespace currency //-------------------- i_miner_handler ----------------------- virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr); - virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()); + virtual bool get_block_template(const create_block_template_params& params, create_block_template_response& resp); + bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()); miner& get_miner(){ return m_miner; } static void init_options(boost::program_options::options_description& desc); diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index 603329e2..3c36798b 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -109,4 +109,6 @@ namespace currency blobdata tx_to_blob(const transaction& b); bool tx_to_blob(const transaction& b, blobdata& b_blob); bool read_keyimages_from_tx(const transaction& tx, std::list& kil); + + } diff --git a/src/currency_core/miner.h b/src/currency_core/miner.h index c1bd83f0..69a4bdc7 100644 --- a/src/currency_core/miner.h +++ b/src/currency_core/miner.h @@ -24,6 +24,7 @@ namespace currency struct i_miner_handler { virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr) = 0; + virtual bool get_block_template(const create_block_template_params& params, create_block_template_response& resp) = 0; virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()) = 0; protected: ~i_miner_handler(){}; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 40ef799c..5a6e89b9 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -793,28 +793,45 @@ namespace currency return false; } - block b = AUTO_VAL_INIT(b); - wide_difficulty_type dt = 0; - currency::pos_entry pe = AUTO_VAL_INIT(pe); - pe.amount = req.pos_amount; - pe.index = req.pos_index; - pe.stake_unlock_time = req.stake_unlock_time; - //pe.keyimage key image will be set in the wallet - //pe.wallet_index is not included in serialization map, TODO: refactoring here - if (!m_core.get_block_template(b, miner_address, stakeholder_address, dt, res.height, req.extra_text, req.pos_block, pe)) + create_block_template_params params = AUTO_VAL_INIT(params); + params.miner_address = miner_address; + params.stakeholder_address = stakeholder_address; + params.ex_nonce = req.extra_text; + params.pos = req.pos_block; + params.pe.amount = req.pos_amount; + params.pe.index = req.pos_index; + params.pe.stake_unlock_time = req.stake_unlock_time; + //params.pe.keyimage key image will be set in the wallet + //params.pe.wallet_index is not included in serialization map, TODO: refactoring here + params.pcustom_fill_block_template_func = nullptr; + if (req.explicit_transaction.size()) + { + transaction tx = AUTO_VAL_INIT(tx); + if (!parse_and_validate_tx_from_blob(req.explicit_transaction, tx)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Wrong parameters: explicit_transaction is invalid"; + LOG_ERROR("Failed to parse explicit_transaction blob"); + return false; + } + params.explicit_txs.push_back(tx); + } + + create_block_template_response resp = AUTO_VAL_INIT(resp); + if (!m_core.get_block_template(params, resp)) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.message = "Internal error: failed to create block template"; LOG_ERROR("Failed to create block template"); return false; } - res.difficulty = dt.convert_to(); - blobdata block_blob = t_serializable_object_to_blob(b); + res.difficulty = resp.diffic.convert_to(); + blobdata block_blob = t_serializable_object_to_blob(resp.b); res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob); - res.prev_hash = string_tools::pod_to_hex(b.prev_id); - + res.prev_hash = string_tools::pod_to_hex(resp.b.prev_id); + res.height = resp.height; //calculate epoch seed res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height)); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 4ff21dec..86fd7506 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -770,7 +770,7 @@ namespace currency { struct request { - //uint64_t reserve_size; //max 255 bytes + blobdata explicit_transaction; std::string extra_text; std::string wallet_address; std::string stakeholder_address; @@ -780,6 +780,7 @@ namespace currency uint64_t stake_unlock_time; BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_BLOB_AS_HEX_STRING(explicit_transaction) KV_SERIALIZE(extra_text) KV_SERIALIZE(wallet_address) KV_SERIALIZE(stakeholder_address); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index eb90f017..f37b1ede 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -2291,15 +2291,32 @@ void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) con incoming_transfers = m_transfers; } //---------------------------------------------------------------------------------------------------- -bool wallet2::generate_packing_transaction_if_needed(transaction& tx) +bool wallet2::generate_packing_transaction_if_needed(transaction& tx, uint64_t fake_outputs_number) { prepare_free_transfers_cache(0); auto it = m_found_free_amounts.find(CURRENCY_BLOCK_REWARD); if (it == m_found_free_amounts.end() || it->second.size() < WALLET_POS_MINT_PACKING_SIZE) return false; + //let's check if we have at least WALLET_POS_MINT_PACKING_SIZE transactions which is ready to go + size_t count = 0; + for (auto it_ind = it->second.begin(); it_ind != it->second.end() && count < WALLET_POS_MINT_PACKING_SIZE; it_ind++) + { + if (is_transfer_ready_to_go(m_transfers[*it_ind], fake_outputs_number)) + ++count; + } + if (count < WALLET_POS_MINT_PACKING_SIZE) + return false; + construct_tx_param ctp = get_default_construct_tx_param(); + currency::tx_destination_entry de = AUTO_VAL_INIT(de); + de.addr.push_back(m_account.get_public_address()); + de.amount = WALLET_POS_MINT_PACKING_SIZE; + ctp.dsts.push_back(de); + ctp.perform_packing = true; + + transfer(ctp, tx, false, nullptr); - + return true; } //---------------------------------------------------------------------------------------------------- std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/) const @@ -2769,6 +2786,12 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request& tmpl_req.pos_index = req.pos_entries[rsp.index].index; tmpl_req.extra_text = m_miner_text_info; tmpl_req.stake_unlock_time = req.pos_entries[rsp.index].stake_unlock_time; + //generate packing tx + transaction pack_tx = AUTO_VAL_INIT(pack_tx); + if (generate_packing_transaction_if_needed(pack_tx, 0)) + { + tx_to_blob(pack_tx, tmpl_req.explicit_transaction); + } m_core_proxy->call_COMMAND_RPC_GETBLOCKTEMPLATE(tmpl_req, tmpl_rsp); WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == CORE_RPC_STATUS_OK, false, "Failed to create block template after kernel hash found!"); @@ -3453,12 +3476,10 @@ bool wallet2::prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake } it->second.erase(it->second.begin()); if (!it->second.size()) - found_free_amounts.erase(it); + m_found_free_amounts.erase(it); } - return prepare_tx_sources(fake_outputs_count, sources, selected_indicies, found_money); - } //---------------------------------------------------------------------------------------------------- bool wallet2::prepare_tx_sources(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust_threshold, std::vector& sources, std::vector& selected_indicies, uint64_t& found_money) @@ -4110,6 +4131,8 @@ void wallet2::prepare_transaction(const construct_tx_param& ctp, finalize_tx_par TIME_MEASURE_START_MS(prepare_tx_sources_time); if (ctp.multisig_id == currency::null_hash) prepare_tx_sources(needed_money, ctp.fake_outputs_count, ctp.dust_policy.dust_threshold, ftp.sources, ftp.selected_transfers, found_money); + else if (ctp.perform_packing) + prepare_tx_sources_for_packing(WALLET_POS_MINT_PACKING_SIZE, 0, ftp.sources, ftp.selected_transfers, found_money); else prepare_tx_sources(ctp.multisig_id, ftp.sources, found_money); TIME_MEASURE_FINISH_MS(prepare_tx_sources_time); @@ -4239,7 +4262,32 @@ void wallet2::transfer(const std::vector& dsts, ctp.tx_outs_attr = tx_outs_attr; ctp.unlock_time = unlock_time; TIME_MEASURE_FINISH(precalculation_time); + transfer(ctp, tx, send_to_network, p_signed_tx_blob_str); +} +//---------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------- +construct_tx_param wallet2::get_default_construct_tx_param_inital() +{ + construct_tx_param ctp = AUTO_VAL_INIT(ctp); + ctp.fee = m_core_runtime_config.tx_default_fee; + ctp.dust_policy = tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD); + ctp.split_strategy_id = tools::detail::ssi_digit; + ctp.tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED; + ctp.shuffle = 0; + return ctp; +} +const construct_tx_param& wallet2::get_default_construct_tx_param() +{ + static construct_tx_param ctp = get_default_construct_tx_param_inital(); + return ctp; +} +//---------------------------------------------------------------------------------------------------- +void wallet2::transfer(const construct_tx_param& ctp, + currency::transaction &tx, + bool send_to_network, + std::string* p_signed_tx_blob_str) +{ TIME_MEASURE_START(prepare_transaction_time); finalize_tx_param ftp = AUTO_VAL_INIT(ftp); prepare_transaction(ctp, ftp); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index bb989655..43d1b2fc 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -541,6 +541,11 @@ namespace tools const std::vector& attachments, currency::transaction& tx); + void transfer(const construct_tx_param& ctp, + currency::transaction &tx, + bool send_to_network, + std::string* p_signed_tx_blob_str); + template void transfer_from_contract( const std::list& owner_keys, @@ -805,7 +810,9 @@ private: void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const wallet_public::wallet_transfer_info& wti) const; void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const std::string& reason = "internal intention") const; - + + construct_tx_param get_default_construct_tx_param_inital(); + const construct_tx_param& get_default_construct_tx_param(); uint64_t get_tx_expiration_median() const; @@ -847,7 +854,7 @@ private: void exception_handler() const; uint64_t get_minimum_allowed_fee_for_contract(const crypto::hash& ms_id); void check_for_free_space_and_throw_if_it_lacks(const std::wstring& path, uint64_t exact_size_needed_if_known = UINT64_MAX); - bool generate_packing_transaction_if_needed(transaction& tx); + bool generate_packing_transaction_if_needed(transaction& tx, uint64_t fake_outputs_number); currency::account_base m_account;