diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index 2d098e32..2bc53f3f 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -81,7 +81,7 @@ namespace epee m_run.store(false, std::memory_order_relaxed); #if defined(WIN32) - ::CloseHandle(::GetStdHandle(STD_INPUT_HANDLE)); + // ::CloseHandle(::GetStdHandle(STD_INPUT_HANDLE)); -- commented out by sowle, I belive we don't need to close this handle here #endif m_request_cv.notify_one(); diff --git a/contrib/epee/include/gzip_encoding.h b/contrib/epee/include/gzip_encoding.h index 6c27c5a8..1d354f78 100644 --- a/contrib/epee/include/gzip_encoding.h +++ b/contrib/epee/include/gzip_encoding.h @@ -260,6 +260,10 @@ namespace net_utils m_pcb.reset(new abstract_callback(cb)); return content_encoding_gzip::update_in(piece_of_transfer); } + + virtual void stop(std::string& OUT collect_remains) override + {} + template bool stop(callback_t cb) {return true;} diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index b0c8838a..fea2f655 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -200,8 +200,26 @@ namespace epee namespace http { + + + struct i_http_client + { + virtual void set_host_name(const std::string& name) = 0; + virtual boost::asio::ip::tcp::socket& get_socket() = 0; + virtual bool connect(const std::string& host, int port, unsigned int timeout) = 0; + virtual bool set_timeouts(unsigned int connection_timeout, unsigned int recv_timeout) = 0; + virtual bool connect(const std::string& host, std::string port) = 0; + virtual bool connect(const std::string& host, const std::string& port, unsigned int timeout) = 0; + virtual bool disconnect() = 0; + virtual bool is_connected() = 0; + virtual bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0; + virtual bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0; + virtual bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0; + }; + template - class http_simple_client_t : public i_target_handler + class http_simple_client_t : public i_target_handler, + public i_http_client { public: @@ -893,25 +911,90 @@ namespace epee typedef http_simple_client_t https_simple_client; + //suitable for both http and https + class http_universal_client: public i_http_client + { + public: + http_universal_client(): m_pclient(new http_simple_client()) + {} + // Forward all calls to m_pclient + void set_host_name(const std::string& name) override + { + m_pclient->set_host_name(name); + } + bool connect(const std::string& host, int port, unsigned int timeout) override + { + return m_pclient->connect(host, port, timeout); + } + boost::asio::ip::tcp::socket& get_socket() override { return m_pclient->get_socket(); } + bool set_timeouts(unsigned int connection_timeout, unsigned int recv_timeout) override { return m_pclient->set_timeouts(connection_timeout, recv_timeout); } + bool connect(const std::string& host, std::string port) override { return m_pclient->connect(host, port); } + bool connect(const std::string& host, const std::string& port, unsigned int timeout) override { return m_pclient->connect(host, port, timeout); } + bool disconnect() override { return m_pclient->disconnect(); } + bool is_connected() override { return m_pclient->is_connected(); } + bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = nullptr, const fields_list& additional_params = fields_list()) override { return m_pclient->invoke_get(uri, body, ppresponse_info, additional_params); } + bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = nullptr, const fields_list& additional_params = fields_list()) override { return m_pclient->invoke(uri, method, body, ppresponse_info, additional_params); } + bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = nullptr, const fields_list& additional_params = fields_list()) override { return m_pclient->invoke_post(uri, body, ppresponse_info, additional_params); } + + void set_is_ssl(bool is_ssl) + { + if (m_is_ssl != is_ssl) + { + if (is_ssl) + { + m_pclient.reset(new https_simple_client()); + } + else + { + m_pclient.reset(new http_simple_client()); + } + m_is_ssl = is_ssl; + } + } + private: + bool m_is_ssl = false; + std::shared_ptr m_pclient; + }; + + + template + void configure_transport(const std::string schema, transport& tr) + {} + inline void configure_transport(const std::string schema, http_universal_client& tr) + { + if (schema == "https") + tr.set_is_ssl(true); + else + tr.set_is_ssl(false); + } + + /************************************************************************/ /* */ /************************************************************************/ template bool invoke_request(const std::string& url, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) { - http::url_content u_c; - bool res = parse_url(url, u_c); + http::url_content u_c{}; + bool r = parse_url(url, u_c); + CHECK_AND_ASSERT_MES(tr.is_connected() || u_c.host.empty() || r, false, "failed to parse url: " << url); + r = invoke_request(u_c, tr, timeout, ppresponse_info, method, body, additional_params); + return r; + } + template + bool invoke_request(const http::url_content& u_c, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) + { if (!tr.is_connected() && !u_c.host.empty()) { - CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); + int port = static_cast(u_c.port); + if (!port) + port = 80;//default for http - if (!u_c.port) - u_c.port = 80;//default for http - - if (!tr.connect(u_c.host, static_cast(u_c.port), timeout)) + configure_transport(u_c.schema, tr); + if (!tr.connect(u_c.host, port, timeout)) { - LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port); + LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << port); return false; } } @@ -937,28 +1020,67 @@ namespace epee } }; - class interruptible_http_client : public http_simple_client - { - std::shared_ptr m_pcb; - bool m_permanent_error = false; - virtual bool handle_target_data(std::string& piece_of_transfer) + class http_https_simple_client_wrapper : virtual public http_simple_client, virtual public https_simple_client + { + public: + http_https_simple_client_wrapper(bool is_ssl, std::shared_ptr ihb_cb) + : m_ssl(is_ssl) + , m_ihb_cb(ihb_cb) + {} + + bool invoke_request(const http::url_content& u_c, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) { - bool r = m_pcb->do_call(piece_of_transfer, m_len_in_summary, m_len_in_summary - m_len_in_remain); + bool r = false; + if (m_ssl) + r = epee::net_utils::http::invoke_request(u_c, static_cast(*this), timeout, ppresponse_info, method, body, additional_params); + else + r = epee::net_utils::http::invoke_request(u_c, static_cast(*this), timeout, ppresponse_info, method, body, additional_params); + return r; + } + + private: + // class i_target_handler + virtual bool handle_target_data(std::string& piece_of_transfer) override + { + bool r = false; + if (m_ssl) + r = m_ihb_cb->do_call(piece_of_transfer, https_simple_client::m_len_in_summary, https_simple_client::m_len_in_summary - https_simple_client::m_len_in_remain); + else + r = m_ihb_cb->do_call(piece_of_transfer, http_simple_client::m_len_in_summary, http_simple_client::m_len_in_summary - http_simple_client::m_len_in_remain); piece_of_transfer.clear(); return r; } + bool m_ssl; + std::shared_ptr m_ihb_cb; + }; + + + class interruptible_http_client + { + bool m_permanent_error = false; public: template bool invoke_cb(callback_t cb, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) { - m_pcb.reset(new idle_handler(cb)); + http::url_content uc{}; + if (!parse_url(url, uc)) + { + LOG_PRINT_L0("HTTP request to " << url << " failed because the URL couldn't be parsed."); + m_permanent_error = true; + return false; + } + bool is_ssl = uc.schema == "https"; + + http_https_simple_client_wrapper wrapper(is_ssl, std::make_shared>(cb)); + const http_response_info* p_hri = nullptr; - bool r = invoke_request(url, *this, timeout, &p_hri, method, body, additional_params); + bool r = wrapper.invoke_request(uc, timeout, &p_hri, method, body, additional_params); + if (p_hri && !(p_hri->m_response_code >= 200 && p_hri->m_response_code < 300)) { - LOG_PRINT_L0("HTTP request to " << url << " failed with code: " << p_hri->m_response_code); + LOG_PRINT_L0(boost::to_upper_copy(uc.schema) << " request to " << url << " failed with code: " << p_hri->m_response_code); m_permanent_error = true; return false; } diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index 1bd2db1c..0eefa26d 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -117,7 +117,7 @@ namespace epee static bool unserialize_stl_container_t_val(stl_container& container, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) { container.clear(); - typename stl_container::value_type exchange_val; + typename stl_container::value_type exchange_val{}; typename t_storage::harray hval_array = stg.get_first_value(pname, exchange_val, hparent_section); if(!hval_array) return false; container.push_back(std::move(exchange_val)); diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h index bd40c688..d27bfca7 100644 --- a/contrib/epee/include/storages/parserse_base_utils.h +++ b/contrib/epee/include/storages/parserse_base_utils.h @@ -23,10 +23,8 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // - - - #pragma once +#include namespace epee { diff --git a/contrib/tor-connect b/contrib/tor-connect index b589edb1..1be2073e 160000 --- a/contrib/tor-connect +++ b/contrib/tor-connect @@ -1 +1 @@ -Subproject commit b589edb1906dccb387cfeded6ed12286c5f0405f +Subproject commit 1be2073ed3da5e9e6e94e8362548df26a22b1bd2 diff --git a/src/common/pre_download.h b/src/common/pre_download.h index 3c46373f..6e4de659 100644 --- a/src/common/pre_download.h +++ b/src/common/pre_download.h @@ -22,7 +22,7 @@ namespace tools #ifndef TESTNET static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2892700.pak", "68e819cd119e4af1b81f1852e42978d662f1e6355124352f3e835db32b5a8230", 6414724487, 10468823040 }; - static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2892700.pak", "605eb4eb0903aa7b3a2a046514ef349d45c7de31d2702fd9dc104ca65705d6eb", 7860127140, 10204872704 }; + static constexpr pre_download_entry c_pre_download_lmdb = { "https://f005.backblazeb2.com/file/zano-predownload/zano_lmdb_95_2892700.pak", "605eb4eb0903aa7b3a2a046514ef349d45c7de31d2702fd9dc104ca65705d6eb", 7860127140, 10204872704 }; #else static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 }; static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 }; diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp index a7c32892..d1f37b0a 100644 --- a/src/connectivity_tool/conn_tool.cpp +++ b/src/connectivity_tool/conn_tool.cpp @@ -414,7 +414,7 @@ bool generate_genesis(const std::string& path_config, uint64_t premine_split_amo std::cout << ENDL << "PROOF PHRASE: " << gcp.proof_string << ENDL; uint64_t block_reward_without_fee = 0; uint64_t block_reward = 0; - construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations); + construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations); currency::blobdata txb = tx_to_blob(bl.miner_tx); //self validate block diff --git a/src/currency_core/basic_pow_helpers.cpp b/src/currency_core/basic_pow_helpers.cpp index b7ee80ca..d029ee19 100644 --- a/src/currency_core/basic_pow_helpers.cpp +++ b/src/currency_core/basic_pow_helpers.cpp @@ -81,7 +81,7 @@ namespace currency { blobdata bd = get_block_hashing_blob(b); - access_nonce_in_block_blob(bd) = 0; + set_nonce_to_blockblob(bd, 0); return crypto::cn_fast_hash(bd.data(), bd.size()); } //--------------------------------------------------------------- diff --git a/src/currency_core/basic_pow_helpers.h b/src/currency_core/basic_pow_helpers.h index 32ded457..62ba7721 100644 --- a/src/currency_core/basic_pow_helpers.h +++ b/src/currency_core/basic_pow_helpers.h @@ -34,13 +34,17 @@ namespace currency void get_block_longhash(const block& b, crypto::hash& res); crypto::hash get_block_longhash(const block& b); - inline uint64_t& access_nonce_in_block_blob(blobdata& bd) + inline uint64_t get_nonce_from_blockblob(const blobdata& bd) { - return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); + uint64_t nonce = 0; + CHECK_AND_ASSERT_MES(bd.size() >= CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET + sizeof(nonce), 0, "Unexpected block buffer size = " << bd.size()); + std::memcpy(&nonce, &bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET], sizeof(nonce)); + return nonce; } - inline const uint64_t& access_nonce_in_block_blob(const blobdata& bd) + inline void set_nonce_to_blockblob(blobdata& bd, const uint64_t nonce) { - return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); + CHECK_AND_ASSERT_MES(bd.size() >= CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET + sizeof(nonce), void(), "Unexpected block buffer size = " << bd.size()); + std::memcpy(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET], &nonce, sizeof(nonce)); } } \ No newline at end of file diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 0d6d41f8..01074e2c 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -30,7 +30,6 @@ #include "common/boost_serialization_helper.h" #include "warnings.h" #include "crypto/hash.h" -#include "miner_common.h" #include "storages/portable_storage_template_helper.h" #include "basic_pow_helpers.h" #include "version.h" @@ -973,6 +972,57 @@ bool blockchain_storage::get_block_by_hash(const crypto::hash &h, block &blk) c return false; } +//------------------------------------------------------------------ +bool blockchain_storage::get_block_reward_by_main_chain_height(const uint64_t height, uint64_t& reward_with_fee) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + static const boost::multiprecision::uint128_t amount_max_mp = UINT64_MAX; + + if (height >= m_db_blocks.size()) + return false; + + boost::multiprecision::uint128_t reward_with_fee_mp{}; + if (height != 0) + reward_with_fee_mp = m_db_blocks[height]->already_generated_coins - m_db_blocks[height - 1]->already_generated_coins; + else + reward_with_fee_mp = m_db_blocks[height]->already_generated_coins; + + if (reward_with_fee_mp > amount_max_mp) + return false; + + reward_with_fee = reward_with_fee_mp.convert_to(); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_block_reward_by_hash(const crypto::hash &h, uint64_t& reward_with_fee) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + static const boost::multiprecision::uint128_t amount_max_mp = UINT64_MAX; + + block_extended_info bei{}; + if (!get_block_extended_info_by_hash(h, bei)) + return false; + + boost::multiprecision::uint128_t reward_with_fee_mp{}; + if (bei.height != 0) + { + block_extended_info bei_prev{}; + if (!get_block_extended_info_by_hash(bei.bl.prev_id, bei_prev)) + return false; + reward_with_fee_mp = bei.already_generated_coins - bei_prev.already_generated_coins; + } + else + { + reward_with_fee_mp = bei.already_generated_coins; + } + + if (reward_with_fee_mp > amount_max_mp) + return false; + + reward_with_fee = reward_with_fee_mp.convert_to(); + return true; +} +//------------------------------------------------------------------ bool blockchain_storage::is_tx_related_to_altblock(crypto::hash tx_id) const { CRITICAL_REGION_LOCAL1(m_alternative_chains_lock); @@ -1589,6 +1639,9 @@ bool blockchain_storage::create_block_template(const create_block_template_param resp.txs_fee = fee; + size_t tx_hardfork_id = 0; + size_t tx_version = get_tx_version_and_hardfork_id(height, m_core_runtime_config.hard_forks, tx_hardfork_id); + /* instead of complicated two-phase template construction and adjustment of cumulative size with block reward we use CURRENCY_COINBASE_BLOB_RESERVED_SIZE as penalty-free coinbase transaction reservation. @@ -1601,7 +1654,8 @@ bool blockchain_storage::create_block_template(const create_block_template_param b.miner_tx, resp.block_reward_without_fee, resp.block_reward, - get_tx_version(height, m_core_runtime_config.hard_forks), + tx_version, + tx_hardfork_id, ex_nonce, CURRENCY_MINER_TX_MAX_OUTS, pos, @@ -6080,6 +6134,7 @@ struct visitor_proxy : public boost::static_visitor bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const { + size_t most_recent_hardfork_id_for_height = m_core_runtime_config.hard_forks.get_the_most_recent_hardfork_id_for_height(block_height); bool var_is_after_hardfork_1_zone = m_core_runtime_config.is_hardfork_active_for_height(1, block_height); bool var_is_after_hardfork_2_zone = m_core_runtime_config.is_hardfork_active_for_height(2, block_height); bool var_is_after_hardfork_3_zone = m_core_runtime_config.is_hardfork_active_for_height(3, block_height); @@ -6218,7 +6273,9 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti if (var_is_after_hardfork_5_zone) { - // additional checks here + CHECK_AND_ASSERT_MES(tx.version >= TRANSACTION_VERSION_POST_HF5, false, "HF5: tx with version " << tx.version << " is not allowed"); + // starting from HF5 each tx must have hardfork_id corresponding to the current active hardfork + CHECK_AND_ASSERT_MES(tx.hardfork_id == most_recent_hardfork_id_for_height, false, "tx's hardfork_id is " << (int)tx.hardfork_id << ", but the current hardfork is " << most_recent_hardfork_id_for_height << ", rejected"); } else { diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 78c75e66..5ebc328c 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -233,6 +233,8 @@ namespace currency size_t get_alternative_blocks_count() const; crypto::hash get_block_id_by_height(uint64_t height) const; bool get_block_by_hash(const crypto::hash &h, block &blk) const; + bool get_block_reward_by_main_chain_height(const uint64_t height, uint64_t& reward_with_fee) const; // only for main chain blocks + bool get_block_reward_by_hash(const crypto::hash &h, uint64_t& reward_with_fee) const; // works for main chain and alt chain blocks bool get_block_extended_info_by_height(uint64_t h, block_extended_info &blk) const; bool get_block_extended_info_by_hash(const crypto::hash &h, block_extended_info &blk) const; bool get_block_by_height(uint64_t h, block &blk) const; diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index d0630089..5b0bfcc2 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -1032,6 +1032,7 @@ namespace currency { public: uint64_t version = 0; + uint8_t hardfork_id = 0; std::vector vin; std::vector extra; std::vector vout; @@ -1044,6 +1045,8 @@ namespace currency FIELD(vin) FIELD(extra) FIELD(vout) + if(version < TRANSACTION_VERSION_POST_HF5) return true; + FIELD(hardfork_id) END_SERIALIZE() }; diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 1d6edf20..06ce2813 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2024 Zano Project +// Copyright (c) 2014-2025 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 @@ -10,7 +10,7 @@ #ifndef TESTNET #define CURRENCY_FORMATION_VERSION 84 #else -#define CURRENCY_FORMATION_VERSION 99 +#define CURRENCY_FORMATION_VERSION 100 #endif #define CURRENCY_GENESIS_NONCE (CURRENCY_FORMATION_VERSION + 101011010121) //bender's nightmare @@ -28,10 +28,11 @@ #define CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX 0x98c8 // auditable addresses start with 'aZx' #define CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX 0x8a49 // auditable integrated addresses start with 'aiZX' #define CURRENCY_MINED_MONEY_UNLOCK_WINDOW 10 -#define CURRENT_TRANSACTION_VERSION 2 +#define CURRENT_TRANSACTION_VERSION 3 #define TRANSACTION_VERSION_INITAL 0 #define TRANSACTION_VERSION_PRE_HF4 1 -#define TRANSACTION_VERSION_POST_HF4 2 +#define TRANSACTION_VERSION_POST_HF4 2 +#define TRANSACTION_VERSION_POST_HF5 3 #define HF1_BLOCK_MAJOR_VERSION 1 #define HF3_BLOCK_MAJOR_VERSION 2 #define HF3_BLOCK_MINOR_VERSION 0 @@ -278,9 +279,9 @@ #define ZANO_HARDFORK_02_AFTER_HEIGHT 0 #define ZANO_HARDFORK_03_AFTER_HEIGHT 0 #define ZANO_HARDFORK_04_AFTER_HEIGHT 100 -#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1712800000ull // block 100, 2024-00-00 00:00:00 UTC +#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1738659600ull // block 100, 2025-00-00 00:00:00 UTC #define ZANO_HARDFORK_05_AFTER_HEIGHT 200 -#define ZANO_HARDFORK_05_MIN_BUILD_VER 356 +#define ZANO_HARDFORK_05_MIN_BUILD_VER 379 #endif diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 8d29c38d..37e67e93 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2012-2013 The Boolberry developers @@ -34,8 +34,10 @@ namespace currency core::core(i_currency_protocol* pprotocol) : m_mempool(m_blockchain_storage, pprotocol) , m_blockchain_storage(m_mempool) +#ifdef CPU_MINING_ENABLED , m_miner(this, m_blockchain_storage) - , m_miner_address(boost::value_initialized()) +#endif + //, m_miner_address(boost::value_initialized()) , m_starter_message_showed(false) , m_critical_error_handler(nullptr) , m_stop_after_height(0) @@ -165,8 +167,10 @@ namespace currency m_mempool.remove_incompatible_txs(); +#ifdef CPU_MINING_ENABLED r = m_miner.init(vm); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner"); +#endif //check if tx_pool module synchronized with blockchaine storage // if (m_blockchain_storage.get_top_block_id() != m_mempool.get_last_core_hash()) @@ -193,8 +197,10 @@ namespace currency { //m_mempool.set_last_core_hash(m_blockchain_storage.get_top_block_id()); +#ifdef CPU_MINING_ENABLED m_miner.stop(); m_miner.deinit(); +#endif m_mempool.deinit(); m_blockchain_storage.deinit(); return true; @@ -274,7 +280,9 @@ namespace currency //----------------------------------------------------------------------------------------------- bool core::get_stat_info(const core_stat_info::params& pr, core_stat_info& st_inf) { +#ifdef CPU_MINING_ENABLED st_inf.mining_speed = m_miner.get_speed(); +#endif st_inf.alternative_blocks = m_blockchain_storage.get_alternative_blocks_count(); st_inf.blockchain_height = m_blockchain_storage.get_current_blockchain_size(); st_inf.tx_pool_size = m_mempool.get_transactions_count(); @@ -405,12 +413,16 @@ namespace currency //----------------------------------------------------------------------------------------------- void core::pause_mine() { +#ifdef CPU_MINING_ENABLED m_miner.pause(); +#endif } //----------------------------------------------------------------------------------------------- void core::resume_mine() { +#ifdef CPU_MINING_ENABLED m_miner.resume(); +#endif } //----------------------------------------------------------------------------------------------- bool core::handle_block_found(const block& b, block_verification_context* p_verification_result, bool need_update_miner_block_template) @@ -422,10 +434,10 @@ namespace currency if (!p_verification_result) p_verification_result = &bvc; - m_miner.pause(); + pause_mine(); misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([this]() { - m_miner.resume(); + resume_mine(); }); TIME_MEASURE_START_MS(time_add_new_block_ms); @@ -520,7 +532,9 @@ namespace currency //----------------------------------------------------------------------------------------------- void core::on_synchronized() { +#ifdef CPU_MINING_ENABLED m_miner.on_synchronized(); +#endif } bool core::get_backward_blocks_sizes(uint64_t from_height, std::vector& sizes, size_t count) { @@ -685,7 +699,9 @@ namespace currency bool core::update_miner_block_template() { notify_blockchain_update_listeners(); +#ifdef CPU_MINING_ENABLED m_miner.on_block_chain_update(); +#endif return true; } //----------------------------------------------------------------------------------------------- @@ -708,7 +724,9 @@ namespace currency m_prune_alt_blocks_interval.do_call([this](){return m_blockchain_storage.prune_aged_alt_blocks();}); m_check_free_space_interval.do_call([this](){ check_free_space(); return true; }); +#ifdef CPU_MINING_ENABLED m_miner.on_idle(); +#endif m_mempool.on_idle(); return true; } diff --git a/src/currency_core/currency_core.h b/src/currency_core/currency_core.h index feeca5f4..637103b1 100644 --- a/src/currency_core/currency_core.h +++ b/src/currency_core/currency_core.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2012-2013 The Boolberry developers @@ -57,7 +57,9 @@ namespace currency 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()); +#ifdef CPU_MINING_ENABLED miner& get_miner(){ return m_miner; } +#endif static void init_options(boost::program_options::options_description& desc); bool init(const boost::program_options::variables_map& vm); bool set_genesis_block(const block& b); @@ -66,7 +68,7 @@ namespace currency uint64_t get_current_tx_version() const; uint64_t get_top_block_height() const; std::string get_config_folder(); - bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const; + bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) const; bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs); bool get_blocks(uint64_t start_offset, size_t count, std::list& blocks); template @@ -136,13 +138,15 @@ namespace currency void check_free_space(); - blockchain_storage m_blockchain_storage; tx_memory_pool m_mempool; + blockchain_storage m_blockchain_storage; i_currency_protocol* m_pprotocol; i_critical_error_handler* m_critical_error_handler; epee::critical_section m_incoming_tx_lock; +#ifdef CPU_MINING_ENABLED miner m_miner; - account_public_address m_miner_address; +#endif + //account_public_address m_miner_address; std::string m_config_folder; uint64_t m_stop_after_height; currency_protocol_stub m_protocol_stub; diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 60024b71..56316dd5 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -393,6 +393,7 @@ namespace currency uint64_t& block_reward_without_fee, uint64_t& block_reward, uint64_t tx_version, + size_t tx_hadrfork_id, const blobdata& extra_nonce /* = blobdata() */, size_t max_outs /* = CURRENCY_MINER_TX_MAX_OUTS */, bool pos /* = false */, @@ -476,6 +477,8 @@ namespace currency CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed."); // tx is not cleared intentionally to allow passing additional args in the extra/attachments tx.version = tx_version; + if (tx.version >= TRANSACTION_VERSION_POST_HF5) + tx.hardfork_id = tx_hadrfork_id; tx_generation_context tx_gen_context{}; tx_gen_context.set_tx_key(tx_one_time_key_to_use ? *tx_one_time_key_to_use : keypair::generate()); @@ -1439,12 +1442,13 @@ namespace currency const std::vector& attachments, transaction& tx, uint64_t tx_version, + size_t tx_hardfork_id, uint64_t unlock_time, uint8_t tx_outs_attr, bool shuffle) { - crypto::secret_key one_time_secret_key = AUTO_VAL_INIT(one_time_secret_key); - return construct_tx(sender_account_keys, sources, destinations, std::vector(), attachments, tx, tx_version, one_time_secret_key, unlock_time, tx_outs_attr, shuffle); + crypto::secret_key one_time_secret_key{}; + return construct_tx(sender_account_keys, sources, destinations, std::vector(), attachments, tx, tx_version, tx_hardfork_id, one_time_secret_key, unlock_time, tx_outs_attr, shuffle); } //--------------------------------------------------------------- @@ -1964,6 +1968,7 @@ namespace currency const std::vector& attachments, transaction& tx, uint64_t tx_version, + size_t tx_hardfork_id, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, uint8_t tx_outs_attr, @@ -1976,7 +1981,7 @@ namespace currency //in case if there is no real targets we use sender credentials to encrypt attachments account_public_address crypt_destination_addr = get_crypt_address_from_destinations(sender_account_keys, destinations); - return construct_tx(sender_account_keys, sources, destinations, extra, attachments, tx, tx_version, one_time_secret_key, unlock_time, + return construct_tx(sender_account_keys, sources, destinations, extra, attachments, tx, tx_version, tx_hardfork_id, one_time_secret_key, unlock_time, crypt_destination_addr, 0, tx_outs_attr, @@ -1990,6 +1995,7 @@ namespace currency const std::vector& attachments, transaction& tx, uint64_t tx_version, + size_t tx_hardfork_id, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, const account_public_address& crypt_destination_addr, @@ -1999,8 +2005,9 @@ namespace currency uint64_t flags) { //extra copy operation, but creating transaction is not sensitive to this - finalize_tx_param ftp = AUTO_VAL_INIT(ftp); + finalize_tx_param ftp{}; ftp.tx_version = tx_version; + ftp.tx_hardfork_id = tx_hardfork_id; ftp.sources = sources; ftp.prepared_destinations = destinations; ftp.extra = extra; @@ -2012,7 +2019,7 @@ namespace currency ftp.shuffle = shuffle; ftp.flags = flags; - finalized_tx ft = AUTO_VAL_INIT(ft); + finalized_tx ft{}; ft.tx = tx; ft.one_time_key = one_time_secret_key; bool r = construct_tx(sender_account_keys, ftp, ft); @@ -2402,6 +2409,9 @@ namespace currency tx.signatures.clear(); tx.version = ftp.tx_version; + if (tx.version >= TRANSACTION_VERSION_POST_HF5) + tx.hardfork_id = ftp.tx_hardfork_id; + if (unlock_time != 0) set_tx_unlock_time(tx, unlock_time); @@ -2819,15 +2829,26 @@ namespace currency //--------------------------------------------------------------- - uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd) + uint64_t get_tx_version_and_hardfork_id(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd, size_t& tx_hardfork_id) { + tx_hardfork_id = hfd.get_the_most_recent_hardfork_id_for_height(tx_expected_block_height); if (!hfd.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, tx_expected_block_height)) { return TRANSACTION_VERSION_PRE_HF4; } + if (!hfd.is_hardfork_active_for_height(ZANO_HARDFORK_05, tx_expected_block_height)) + { + return TRANSACTION_VERSION_POST_HF4; + } return CURRENT_TRANSACTION_VERSION; } //--------------------------------------------------------------- + uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd) + { + [[maybe_unused]] size_t tx_hardfork_id{}; + return get_tx_version_and_hardfork_id(tx_expected_block_height, hfd, tx_hardfork_id); + } + //--------------------------------------------------------------- // TODO @#@# this function is obsolete and needs to be re-written uint64_t get_reward_from_miner_tx(const transaction& tx) { diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 399a6d90..b3cfbeed 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -163,6 +163,7 @@ namespace currency uint64_t expiration_time; crypto::public_key spend_pub_key; // only for validations uint64_t tx_version; + size_t tx_hardfork_id = 0; uint64_t mode_separate_fee = 0; epee::misc_utils::events_dispatcher* pevents_dispatcher = nullptr; @@ -187,6 +188,7 @@ namespace currency FIELD(expiration_time) FIELD(spend_pub_key) FIELD(tx_version) + FIELD(tx_hardfork_id) FIELD(mode_separate_fee) if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) { @@ -295,6 +297,7 @@ namespace currency uint64_t& block_reward_without_fee, uint64_t& block_reward, uint64_t tx_version, + size_t tx_hadrfork_id, const blobdata& extra_nonce = blobdata(), size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, bool pos = false, @@ -317,9 +320,11 @@ namespace currency const std::vector& attachments, transaction& tx, uint64_t tx_version, + size_t tx_hardfork_id, uint64_t unlock_time, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED, bool shuffle = true); + bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, @@ -327,6 +332,7 @@ namespace currency const std::vector& attachments, transaction& tx, uint64_t tx_version, + size_t tx_hardfork_id, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED, @@ -340,6 +346,7 @@ namespace currency const std::vector& attachments, transaction& tx, uint64_t tx_version, + size_t tx_hardfork_id, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, const account_public_address& crypt_account, @@ -348,6 +355,7 @@ namespace currency bool shuffle = true, uint64_t flags = 0); + uint64_t get_tx_version_and_hardfork_id(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd, size_t& tx_hardfork_id); // returns tx version and tx hardfork id based on the height of the block where the transaction is expected to be uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd); // returns tx version based on the height of the block where the transaction is expected to be bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& param, finalized_tx& result); bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key); diff --git a/src/currency_core/miner.cpp b/src/currency_core/miner.cpp index 109d9966..dc37f3f6 100644 --- a/src/currency_core/miner.cpp +++ b/src/currency_core/miner.cpp @@ -31,6 +31,64 @@ using namespace epee; namespace currency { +#ifndef CPU_MINING_ENABLED + + // CPU mining disabled + // currency::miner stub implementation + + /* + miner::miner(i_miner_handler* phandler, blockchain_storage& bc) + {} + miner::~miner() + {} + bool miner::init(const boost::program_options::variables_map& vm) + { + return true; + } + bool miner::deinit() + { + return true; + } + void miner::init_options(boost::program_options::options_description& desc) + {} + bool miner::start(const account_public_address& adr, size_t threads_count) + { + return false; + } + bool miner::stop() + { + return false; + } + bool miner::is_mining() + { + return false; + } + void miner::do_print_hashrate(bool do_hr) + {} + void miner::pause() + {} + void miner::resume() + {} + bool miner::on_block_chain_update() + { + return false; + } + uint64_t miner::get_speed() + { + return 0; + } + void miner::on_synchronized() + {} + bool miner::on_idle() + { + return false; + } + + // end of currency::miner stub implementation + */ +#else + + namespace { const command_line::arg_descriptor arg_extra_messages ("extra-messages-file", "Specify file for extra messages to include into coinbase transactions"); @@ -379,5 +437,8 @@ namespace currency return true; } //----------------------------------------------------------------------------------------------------- -} + +#endif // #ifndef CPU_MINING_ENABLED + +} // namespace currency diff --git a/src/currency_core/miner.h b/src/currency_core/miner.h index c8a37225..674bb4d2 100644 --- a/src/currency_core/miner.h +++ b/src/currency_core/miner.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2025 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2012-2013 The Boolberry developers @@ -7,6 +7,10 @@ #pragma once +#ifdef TESTNET +#define CPU_MINING_ENABLED // disable CPU mining capabilities in mainnet +#endif // #ifndef TESTNET + #include #include #include @@ -30,6 +34,29 @@ namespace currency ~i_miner_handler(){}; }; + inline + static bool find_nonce_for_given_block(block& bl, const wide_difficulty_type& diffic, uint64_t height) + { + bl.nonce = 0; + blobdata bd = get_block_hashing_blob(bl); + crypto::hash bd_hash = crypto::cn_fast_hash(bd.data(), bd.size()); + //uint64_t& nonce_ref = access_nonce_in_block_blob(bd); + //nonce_ref = 0; + + for(; bl.nonce != std::numeric_limits::max(); bl.nonce++) + { + crypto::hash h = get_block_longhash(height, bd_hash, bl.nonce); + if(check_hash(h, diffic)) + { + LOG_PRINT_L1("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << " (diff:" << diffic << "), ts: " << bl.timestamp); + return true; + } + } + return false; + } + +#ifdef CPU_MINING_ENABLED + /************************************************************************/ /* */ /************************************************************************/ @@ -54,27 +81,6 @@ namespace currency void resume(); void do_print_hashrate(bool do_hr); - inline - static bool find_nonce_for_given_block(block& bl, const wide_difficulty_type& diffic, uint64_t height) - { - bl.nonce = 0; - blobdata bd = get_block_hashing_blob(bl); - crypto::hash bd_hash = crypto::cn_fast_hash(bd.data(), bd.size()); - //uint64_t& nonce_ref = access_nonce_in_block_blob(bd); - //nonce_ref = 0; - - for(; bl.nonce != std::numeric_limits::max(); bl.nonce++) - { - crypto::hash h = get_block_longhash(height, bd_hash, bl.nonce); - if(check_hash(h, diffic)) - { - LOG_PRINT_L1("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << " (diff:" << diffic << "), ts: " << bl.timestamp); - return true; - } - } - return false; - } - private: bool set_block_template(const block& bl, const wide_difficulty_type& diffic, uint64_t height); bool worker_thread(); @@ -122,7 +128,7 @@ namespace currency bool m_do_mining; }; -} - +#endif // #ifdef CPU_MINING_ENABLED +} // namespace currency diff --git a/src/currency_core/miner_common.h b/src/currency_core/miner_common.h deleted file mode 100644 index 9c6db391..00000000 --- a/src/currency_core/miner_common.h +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2014-2018 Zano Project -// Copyright (c) 2014-2018 The Louisdor Project -// Copyright (c) 2012-2013 The Boolberry developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once - diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index b9c7a524..94b77505 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -229,7 +229,8 @@ namespace currency template uint64_t t_currency_protocol_handler::get_max_seen_height() { - return m_max_height_seen; + uint64_t max_seen = m_max_height_seen; + return std::max(max_seen, m_core.get_blockchain_storage().get_top_block_height()); } //------------------------------------------------------------------------------------------------------------------------ template diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index f5f768fc..4e5d0de0 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -126,7 +126,6 @@ int main(int argc, char* argv[]) log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet", false); - LOG_PRINT_L0("Starting..."); tools::signal_handler::install_fatal([](int sig_number, void* address) { LOG_ERROR("\n\nFATAL ERROR\nsig: " << sig_number << ", address: " << address); @@ -175,7 +174,9 @@ int main(int argc, char* argv[]) currency::core_rpc_server::init_options(desc_cmd_sett); typedef nodetool::node_server > p2psrv_t; p2psrv_t::init_options(desc_cmd_sett); +#ifdef CPU_MINING_ENABLED currency::miner::init_options(desc_cmd_sett); +#endif bc_services::bc_offers_service::init_options(desc_cmd_sett); currency::stratum_server::init_options(desc_cmd_sett); tools::db::db_backend_selector::init_options(desc_cmd_sett); @@ -184,6 +185,7 @@ int main(int argc, char* argv[]) desc_options.add(desc_cmd_only).add(desc_cmd_sett); po::variables_map vm; + bool exit_requested = false; bool r = command_line::handle_error_helper(desc_options, [&]() { po::store(po::parse_command_line(argc, argv, desc_options), vm); @@ -192,7 +194,14 @@ int main(int argc, char* argv[]) { std::cout << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL; std::cout << desc_options << std::endl; - return false; + exit_requested = true; + return true; + } + else if (command_line::get_arg(vm, command_line::arg_version)) + { + std::cout << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ENDL << ENDL; + exit_requested = true; + return true; } std::string data_dir = command_line::get_arg(vm, command_line::arg_data_dir); @@ -214,9 +223,13 @@ int main(int argc, char* argv[]) return true; }); + if (!r) return EXIT_FAILURE; + if (exit_requested) + return EXIT_SUCCESS; + //set up logging options std::string log_dir; std::string log_file_name = log_space::log_singletone::get_default_log_file(); @@ -238,6 +251,7 @@ int main(int argc, char* argv[]) return EXIT_SUCCESS; } + LOG_PRINT_L0("Starting..."); // stratum server is enabled if any of its options present bool stratum_enabled = currency::stratum_server::should_start(vm); diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index 1b26fb73..2920c118 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 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 @@ -49,12 +49,14 @@ public: 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("print_blocked_ips", boost::bind(&daemon_commands_handler::print_blocked_ips, this, ph::_1), "Print ip address blacklists"); +#ifdef CPU_MINING_ENABLED 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)"); - m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_commands_handler::print_pool_sh, this, ph::_1), "Print transaction pool (short format)"); m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_commands_handler::show_hr, this, ph::_1), "Start showing hash rate"); m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_commands_handler::hide_hr, this, ph::_1), "Stop showing hash rate"); +#endif + m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_commands_handler::print_pool, this, ph::_1), "Print transaction pool (long format)"); + m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_commands_handler::print_pool_sh, this, ph::_1), "Print transaction pool (short format)"); m_cmd_binder.set_handler("save", boost::bind(&daemon_commands_handler::save, this, ph::_1), "Save blockchain"); m_cmd_binder.set_handler("print_daemon_stat", boost::bind(&daemon_commands_handler::print_daemon_stat, this, ph::_1), "Print daemon stat"); m_cmd_binder.set_handler("print_debug_stat", boost::bind(&daemon_commands_handler::print_debug_stat, this, ph::_1), "Print debug stat info"); @@ -184,25 +186,6 @@ private: return true; } - //-------------------------------------------------------------------------------- - bool show_hr(const std::vector& args) - { - if (!m_srv.get_payload_object().get_core().get_miner().is_mining()) - { - std::cout << "Mining is not started. You need start mining before you can see hash rate." << ENDL; - } - else - { - m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true); - } - return true; - } - //-------------------------------------------------------------------------------- - bool hide_hr(const std::vector& args) - { - m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(false); - return true; - } //-------------------------------------------------------------------------------- bool print_bc_outs(const std::vector& args) { @@ -910,7 +893,9 @@ private: { LOG_PRINT_L0("Pool state: " << ENDL << m_srv.get_payload_object().get_core().print_pool(true)); return true; - } //-------------------------------------------------------------------------------- + } + //-------------------------------------------------------------------------------- +#ifdef CPU_MINING_ENABLED bool start_mining(const std::vector& args) { if (!args.size()) @@ -941,6 +926,26 @@ private: m_srv.get_payload_object().get_core().get_miner().stop(); return true; } + //-------------------------------------------------------------------------------- + bool show_hr(const std::vector& args) + { + if (!m_srv.get_payload_object().get_core().get_miner().is_mining()) + { + std::cout << "Mining is not started. You need start mining before you can see hash rate." << ENDL; + } + else + { + m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(true); + } + return true; + } + //-------------------------------------------------------------------------------- + bool hide_hr(const std::vector& args) + { + m_srv.get_payload_object().get_core().get_miner().do_print_hashrate(false); + return true; + } +#endif // #ifdef CPU_MINING_ENABLED //-------------------------------------------------------------------------------- bool forecast_difficulty(const std::vector& args) { diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 950c93af..30ca6bc8 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -959,7 +959,12 @@ bool MainWindow::init_backend(int argc, char* argv[]) QString MainWindow::is_remnotenode_mode_preconfigured(const QString& param) { TRY_ENTRY(); - return API_RETURN_CODE_FALSE; + view::api_response ar{}; + if (m_backend.is_remote_node_mode()) + ar.error_code = API_RETURN_CODE_TRUE; + else + ar.error_code = API_RETURN_CODE_FALSE; + return MAKE_RESPONSE(ar); CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 7cd0e5e5..dbca6947 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 7cd0e5e54a0d692ea819b9653f60a1cd5512dc2b +Subproject commit dbca694737496434ef9c7da765ee6aafd7f90158 diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 88938641..46fe0a41 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -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 @@ -925,6 +925,7 @@ namespace currency return call_res; } //------------------------------------------------------------------------------------------------------------------------------ +#ifdef CPU_MINING_ENABLED bool core_rpc_server::on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx) { CHECK_CORE_READY(); @@ -955,6 +956,7 @@ namespace currency res.status = API_RETURN_CODE_OK; return true; } +#endif // #ifdef CPU_MINING_ENABLED //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx) { @@ -1156,16 +1158,22 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ - uint64_t core_rpc_server::get_block_reward(const block& blk) + uint64_t core_rpc_server::get_block_reward(const block& blk, const crypto::hash& h) { + if (blk.miner_tx.version >= TRANSACTION_VERSION_POST_HF4) + { + uint64_t reward_with_fee = 0; + m_core.get_blockchain_storage().get_block_reward_by_hash(h, reward_with_fee); + return reward_with_fee; + } + + // legacy version, pre HF4 uint64_t reward = 0; BOOST_FOREACH(const auto& out, blk.miner_tx.vout) { VARIANT_SWITCH_BEGIN(out); VARIANT_CASE_CONST(tx_out_bare, out) reward += out.amount; - VARIANT_CASE_CONST(tx_out_zarcanum, out) - //@#@ VARIANT_SWITCH_END(); } return reward; @@ -1173,6 +1181,7 @@ namespace currency //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response) { + crypto::hash block_hash = get_block_hash(blk); response.major_version = blk.major_version; response.minor_version = blk.minor_version; response.timestamp = blk.timestamp; @@ -1181,9 +1190,9 @@ namespace currency response.orphan_status = orphan_status; response.height = get_block_height(blk); response.depth = m_core.get_current_blockchain_size() - response.height - 1; - response.hash = string_tools::pod_to_hex(get_block_hash(blk)); + response.hash = string_tools::pod_to_hex(block_hash); response.difficulty = m_core.get_blockchain_storage().block_difficulty(response.height).convert_to(); - response.reward = get_block_reward(blk); + response.reward = get_block_reward(blk, block_hash); return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index e95f5a41..c0a089ae 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -45,9 +45,11 @@ namespace currency bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res, connection_context& cntx); bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res, connection_context& cntx); bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx); - bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx); + bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res, connection_context& cntx); +#ifdef CPU_MINING_ENABLED bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx); bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx); +#endif 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_outs3(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::response& res, connection_context& cntx); @@ -56,7 +58,7 @@ namespace currency bool on_get_tx_pool(const COMMAND_RPC_GET_TX_POOL::request& req, COMMAND_RPC_GET_TX_POOL::response& res, connection_context& cntx); bool on_check_keyimages(const COMMAND_RPC_CHECK_KEYIMAGES::request& req, COMMAND_RPC_CHECK_KEYIMAGES::response& res, connection_context& cntx); bool on_rpc_get_blocks_details(const COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_BLOCKS_DETAILS::response& res, connection_context& cntx); - bool on_force_relaey_raw_txs(const COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& req, COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& res, connection_context& cntx); + bool on_force_relaey_raw_txs(const COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& req, COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& res, connection_context& cntx); bool on_get_offers_ex(const COMMAND_RPC_GET_OFFERS_EX::request& req, COMMAND_RPC_GET_OFFERS_EX::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); @@ -107,9 +109,11 @@ namespace currency MAP_URI_AUTO_JON2("/getheight", on_get_height, COMMAND_RPC_GET_HEIGHT) MAP_URI_AUTO_JON2("/gettransactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS) MAP_URI_AUTO_JON2("/sendrawtransaction", on_send_raw_tx, COMMAND_RPC_SEND_RAW_TX) - MAP_URI_AUTO_JON2("/force_relay", on_force_relaey_raw_txs, COMMAND_RPC_FORCE_RELAY_RAW_TXS) + MAP_URI_AUTO_JON2("/force_relay", on_force_relaey_raw_txs, COMMAND_RPC_FORCE_RELAY_RAW_TXS) +#ifdef CPU_MINING_ENABLED MAP_URI_AUTO_JON2("/start_mining", on_start_mining, COMMAND_RPC_START_MINING) MAP_URI_AUTO_JON2("/stop_mining", on_stop_mining, COMMAND_RPC_STOP_MINING) +#endif MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO) // binary RPCs MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST) @@ -182,7 +186,7 @@ namespace currency bool check_core_ready_(const std::string& calling_method); //utils - uint64_t get_block_reward(const block& blk); + uint64_t get_block_reward(const block& blk, const crypto::hash& h); bool fill_block_header_response(const block& blk, bool orphan_status, block_header_response& response); void set_session_blob(const std::string& session_id, const currency::block& blob); bool get_session_blob(const std::string& session_id, currency::block& blob); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 9a5d07e2..ef5d36fa 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -288,8 +288,10 @@ simple_wallet::simple_wallet() m_refresh_progress_reporter(*this), m_offline_mode(false) { +#ifdef CPU_MINING_ENABLED m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, ph::_1), "start_mining - Start mining in daemon"); m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon"); +#endif // #ifdef CPU_MINING_ENABLED m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, ph::_1), "Resynchronize transactions and balance"); m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "[raw] Show current wallet balance, with 'raw' param it displays all assets without filtering against whitelists"); m_cmd_binder.set_handler("show_staking_history", boost::bind(&simple_wallet::show_staking_history, this, ph::_1), "show_staking_history [2] - Show staking transfers, if option provided - number of days for history to display"); @@ -761,6 +763,7 @@ bool simple_wallet::save(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- +#ifdef CPU_MINING_ENABLED bool simple_wallet::start_mining(const std::vector& args) { if (!try_connect_to_daemon()) @@ -815,6 +818,7 @@ bool simple_wallet::stop_mining(const std::vector& args) fail_msg_writer() << "mining has NOT been stopped: " << err; return true; } +#endif // #ifdef CPU_MINING_ENABLED //---------------------------------------------------------------------------------------------------- void simple_wallet::on_new_block(uint64_t height, const currency::block& block) { @@ -3227,20 +3231,23 @@ int main(int argc, char* argv[]) po::options_description desc_all; desc_all.add(desc_general).add(desc_params); po::variables_map vm; + bool exit_requested = false; bool r = command_line::handle_error_helper(desc_all, [&]() { po::store(command_line::parse_command_line(argc, argv, desc_general, true), vm); if (command_line::get_arg(vm, command_line::arg_help)) { - success_msg_writer() << "Usage: simplewallet [--wallet-file=|--generate-new-wallet=] [--daemon-address=:] []"; + success_msg_writer() << "Usage: simplewallet [--wallet-file=|--generate-new[-auditable]-wallet=] [--daemon-address=:] []"; success_msg_writer() << desc_all << '\n' << sw->get_commands_str(); - return false; + exit_requested = true; + return true; } else if (command_line::get_arg(vm, command_line::arg_version)) { success_msg_writer() << CURRENCY_NAME << " wallet v" << PROJECT_VERSION_LONG; - return false; + exit_requested = true; + return true; } auto parser = po::command_line_parser(argc, argv).options(desc_params).positional(positional_options); @@ -3248,8 +3255,13 @@ int main(int argc, char* argv[]) po::notify(vm); return true; }); + if (!r) return EXIT_FAILURE; + + if (exit_requested) + return EXIT_SUCCESS; + //set up logging options log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index d8bbb5d8..d660e75c 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -50,8 +50,10 @@ namespace currency bool close_wallet(); bool help(const std::vector &args = std::vector()); +#ifdef CPU_MINING_ENABLED bool start_mining(const std::vector &args); bool stop_mining(const std::vector &args); +#endif // #ifdef CPU_MINING_ENABLED bool refresh(const std::vector &args); bool show_balance(const std::vector &args = std::vector()); bool list_recent_transfers(const std::vector& args); diff --git a/src/stratum/stratum_server.cpp b/src/stratum/stratum_server.cpp index 4cfa686a..95729637 100644 --- a/src/stratum/stratum_server.cpp +++ b/src/stratum/stratum_server.cpp @@ -402,11 +402,11 @@ namespace #endif m_blockchain_last_block_id = top_block_id; - m_block_template_hash_blob = get_block_hashing_blob(m_block_template); - if (access_nonce_in_block_blob(m_block_template_hash_blob) != 0) + m_block_template_hash_blob = get_block_hashing_blob(m_block_template); + if (get_nonce_from_blockblob(m_block_template_hash_blob) != 0) { LOG_PRINT_RED("non-zero nonce in generated block template", LOG_LEVEL_0); - access_nonce_in_block_blob(m_block_template_hash_blob) = 0; + set_nonce_to_blockblob(m_block_template_hash_blob, 0); } m_prev_block_template_ethash = m_block_template_ethash; m_block_template_ethash = crypto::cn_fast_hash(m_block_template_hash_blob.data(), m_block_template_hash_blob.size()); diff --git a/src/version.h.in b/src/version.h.in index fc037031..db671fe0 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -4,10 +4,10 @@ #define BUILD_COMMIT_ID "@VERSION@" #define PROJECT_MAJOR_VERSION "2" -#define PROJECT_MINOR_VERSION "0" -#define PROJECT_REVISION "1" +#define PROJECT_MINOR_VERSION "1" +#define PROJECT_REVISION "0" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 367 +#define PROJECT_VERSION_BUILD_NO 379 #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 38907e37..5e82efa4 100644 --- a/src/wallet/core_default_rpc_proxy.cpp +++ b/src/wallet/core_default_rpc_proxy.cpp @@ -167,6 +167,15 @@ namespace tools epee::net_utils::parse_url(m_daemon_address, u); if (!u.port) u.port = 8081; + if (u.schema == "https") + { + m_http_client.set_is_ssl(true); + } + else + { + m_http_client.set_is_ssl(false); + } + bool r = m_http_client.connect(u.host, std::to_string(u.port), m_connection_timeout); if (r) { diff --git a/src/wallet/core_default_rpc_proxy.h b/src/wallet/core_default_rpc_proxy.h index 7eb94397..b693fca6 100644 --- a/src/wallet/core_default_rpc_proxy.h +++ b/src/wallet/core_default_rpc_proxy.h @@ -134,7 +134,7 @@ namespace tools } epee::critical_section m_lock; - epee::net_utils::http::http_simple_client m_http_client; + epee::net_utils::http::http_universal_client m_http_client; std::string m_daemon_address; unsigned int m_connection_timeout; diff --git a/src/wallet/view_iface.h b/src/wallet/view_iface.h index dce4b5ee..91af1f9e 100644 --- a/src/wallet/view_iface.h +++ b/src/wallet/view_iface.h @@ -484,12 +484,14 @@ public: bool is_online; bool last_daemon_is_disconnected; bool is_server_busy; + bool is_remote_node_mode; uint64_t last_proxy_communicate_timestamp; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(is_online) - KV_SERIALIZE(is_server_busy) KV_SERIALIZE(last_daemon_is_disconnected) + KV_SERIALIZE(is_server_busy) + KV_SERIALIZE(is_remote_node_mode) KV_SERIALIZE(last_proxy_communicate_timestamp) END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 5ab899dd..e6e13d35 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1162,7 +1162,7 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept //build transaction currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); prepare_transaction(construct_param, ftp, msc); mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been accepted with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">"); @@ -1182,10 +1182,10 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept *p_acceptance_tx = tx; } //--------------------------------------------------------------------------------- -uint64_t wallet2::get_current_tx_version() +uint64_t wallet2::get_current_tx_version_and_hardfork_id(size_t& tx_hardfork_id) { uint64_t tx_expected_block_height = get_top_block_height() + 1; - return currency::get_tx_version(tx_expected_block_height, this->m_core_runtime_config.hard_forks); + return currency::get_tx_version_and_hardfork_id(tx_expected_block_height, this->m_core_runtime_config.hard_forks, tx_hardfork_id); } //--------------------------------------------------------------------------------- void wallet2::finish_contract(const crypto::hash& contract_id, const std::string& release_type, currency::transaction* p_release_tx /* = nullptr */) @@ -1299,7 +1299,7 @@ void wallet2::request_cancel_contract(const crypto::hash& contract_id, uint64_t construct_param.split_strategy_id = get_current_split_strategy(); currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); prepare_transaction(construct_param, ftp); currency::transaction tx = AUTO_VAL_INIT(tx); crypto::secret_key sk = AUTO_VAL_INIT(sk); @@ -2116,6 +2116,12 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop } else { + //if first synchronized block in the wallet accidently became orphaned we need to force wallet to resync + if(this->m_minimum_height == height) + { + full_reset_needed = true; + } + //this should happen ONLY after block been matched, if not then is internal error if (full_reset_needed) { @@ -2393,7 +2399,7 @@ bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& currency::finalized_tx ftx{}; currency::finalize_tx_param ftp{}; ftp.pevents_dispatcher = &m_debug_events_dispatcher; - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); if (!prepare_tx_sources(decoys_count, /*use_all_decoys_if_found_less_than_required*/ true, ftp.sources, group.tids)) { @@ -3756,6 +3762,10 @@ bool wallet2::balance(std::unordered_mapget_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); prepare_transaction(construct_params, ftp); crypto::secret_key sk = AUTO_VAL_INIT(sk); finalize_transaction(ftp, tx_release_template, sk, false); @@ -5937,7 +5947,7 @@ void wallet2::build_escrow_release_templates(crypto::hash multisig_id, construct_params.extra.push_back(tsa); { currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); prepare_transaction(construct_params, ftp); crypto::secret_key sk = AUTO_VAL_INIT(sk); finalize_transaction(ftp, tx_burn_template, sk, false); @@ -5958,7 +5968,7 @@ void wallet2::build_escrow_cancel_template(crypto::hash multisig_id, construct_tx_param construct_params = AUTO_VAL_INIT(construct_params); currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); construct_params.fee = it->second.amount() - (ecrow_details.amount_a_pledge + ecrow_details.amount_to_pay + ecrow_details.amount_b_pledge); construct_params.multisig_id = multisig_id; construct_params.split_strategy_id = get_current_split_strategy(); @@ -6041,7 +6051,7 @@ void wallet2::build_escrow_template(const bc_services::contract_private_details& } currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); prepare_transaction(ctp, ftp); selected_transfers = ftp.selected_transfers; @@ -6177,7 +6187,7 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details& ctp.unlock_time = unlock_time; currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); try { prepare_transaction(ctp, ftp); @@ -6351,7 +6361,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); ftp.mode_separate_fee = ctp.fee; - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); prepare_transaction(ctp, ftp); selected_transfers = ftp.selected_transfers; @@ -6580,7 +6590,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa //build transaction currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); ftp.gen_context = ionic_context.gen_context; prepare_transaction(construct_param, ftp, msc); @@ -8149,7 +8159,7 @@ void wallet2::transfer(construct_tx_param& ctp, TIME_MEASURE_START(prepare_transaction_time); currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); ftp.pevents_dispatcher = &m_debug_events_dispatcher; - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); if (!prepare_transaction(ctp, ftp)) { result.was_not_prepared = true; @@ -8276,7 +8286,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public } currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); - ftp.tx_version = this->get_current_tx_version(); + ftp.tx_version = get_current_tx_version_and_hardfork_id(ftp.tx_hardfork_id); bool is_hf4 = this->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM); if (!payment_id.empty()) set_payment_id_to_tx(ftp.attachments, payment_id, is_hf4); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 8fcced41..cc4d8f53 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -857,7 +857,7 @@ private: bool handle_cancel_proposal(wallet_public::wallet_transfer_info& wti, const bc_services::escrow_cancel_templates_body& ectb, const std::vector& decrypted_attach); bool handle_expiration_list(uint64_t tx_expiration_ts_median); void handle_contract_expirations(uint64_t tx_expiration_ts_median); - uint64_t get_current_tx_version(); + uint64_t get_current_tx_version_and_hardfork_id(size_t& tx_hardfork_id); 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; void load_votes_config(); diff --git a/src/wallet/wallet_chain_shortener.cpp b/src/wallet/wallet_chain_shortener.cpp index 77c5d82c..39d37c75 100644 --- a/src/wallet/wallet_chain_shortener.cpp +++ b/src/wallet/wallet_chain_shortener.cpp @@ -217,7 +217,7 @@ void wallet_chain_shortener::check_if_block_matched(uint64_t i, const crypto::ha } return; } - if (!m_last_20_blocks.empty() && i > m_last_20_blocks.begin()->first) + if (!m_last_20_blocks.empty() && i >= m_last_20_blocks.begin()->first) { //must be in short sequence (m_last_20_blocks) //self check diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 74db48f9..4f8e8022 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -321,13 +321,21 @@ namespace wallet_public uint64_t unlocked = 0; uint64_t awaiting_in = 0; uint64_t awaiting_out = 0; + + uint64_t outs_count = 0; + uint64_t outs_amount_min = 0; + uint64_t outs_amount_max = 0; //v2 BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(total) DOC_DSCR("Total coins available(including locked)") DOC_EXMP(100000000000000) DOC_END - KV_SERIALIZE(unlocked) DOC_DSCR("Unlocked coins available(the ones that could be used right now)") DOC_EXMP(50000000000000) DOC_END - KV_SERIALIZE(awaiting_in) DOC_DSCR("Unconfirmed amount for receive") DOC_EXMP(1000000000000) DOC_END - KV_SERIALIZE(awaiting_out) DOC_DSCR("Unconfirmed amount for send") DOC_EXMP(2000000000000) DOC_END + KV_SERIALIZE(total) DOC_DSCR("Total coins available(including locked)") DOC_EXMP(100000000000000) DOC_END + KV_SERIALIZE(unlocked) DOC_DSCR("Unlocked coins available(the ones that could be used right now)") DOC_EXMP(50000000000000) DOC_END + KV_SERIALIZE(awaiting_in) DOC_DSCR("Unconfirmed amount for receive") DOC_EXMP(1000000000000) DOC_END + KV_SERIALIZE(awaiting_out) DOC_DSCR("Unconfirmed amount for send") DOC_EXMP(2000000000000) DOC_END + + KV_SERIALIZE(outs_count) DOC_DSCR("Number of total unspent outputs (including locked)") DOC_EXMP(7) DOC_END + KV_SERIALIZE(outs_amount_min) DOC_DSCR("Output's minimum amount") DOC_EXMP(2000000000000) DOC_END + KV_SERIALIZE(outs_amount_max) DOC_DSCR("Output's maximum amount") DOC_EXMP(2000000000000) DOC_END END_KV_SERIALIZE_MAP() }; diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 8859ec8d..caa6c9ef 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -201,7 +201,9 @@ bool wallets_manager::init_command_line(int argc, char* argv[], std::string& fai currency::core::init_options(desc_cmd_sett); currency::core_rpc_server::init_options(desc_cmd_sett); nodetool::node_server >::init_options(desc_cmd_sett); +#ifdef CPU_MINING_ENABLED currency::miner::init_options(desc_cmd_sett); +#endif bc_services::bc_offers_service::init_options(desc_cmd_sett); tools::db::db_backend_selector::init_options(desc_cmd_sett); #endif @@ -1635,10 +1637,11 @@ bool wallets_manager::get_is_remote_daemon_connected() std::string wallets_manager::get_connectivity_status() { - view::general_connectivity_info gci = AUTO_VAL_INIT(gci); + view::general_connectivity_info gci{}; gci.is_online = get_is_remote_daemon_connected(); gci.last_daemon_is_disconnected = m_pproxy_diganostic_info->last_daemon_is_disconnected; gci.is_server_busy = m_pproxy_diganostic_info->is_busy; + gci.is_remote_node_mode = m_remote_node_mode; gci.last_proxy_communicate_timestamp = m_rpc_proxy->get_last_success_interract_time(); return epee::serialization::store_t_to_json(gci); } diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index 4e7f73a0..1a804726 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -178,6 +178,7 @@ public: std::string add_custom_asset_id(uint64_t wallet_id, const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_descriptor); std::string delete_custom_asset_id(uint64_t wallet_id, const crypto::public_key& asset_id); bool is_core_initialized() { return m_core_initialized;} + bool is_remote_node_mode() const { return m_remote_node_mode; } private: void main_worker(const po::variables_map& vm); diff --git a/tests/core_tests/alias_tests.cpp b/tests/core_tests/alias_tests.cpp index b8a1e4fd..266e4164 100644 --- a/tests/core_tests/alias_tests.cpp +++ b/tests/core_tests/alias_tests.cpp @@ -381,7 +381,7 @@ bool gen_alias_tests::check_too_many_aliases_registration(currency::core& c, siz CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == total_alias_to_gen, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count() << ", expected: " << total_alias_to_gen); // complete block template and try to process it - r = miner::find_nonce_for_given_block(b, diff, height); + r = find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); @@ -975,7 +975,9 @@ bool gen_alias_too_much_reward::generate(std::vector& events) d.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id | tx_destination_entry_flags::tdef_zero_amount_blinding_mask; transaction tx_0{}; crypto::secret_key sk{}; - r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ ai }), empty_attachment, tx_0, get_tx_version_from_events(events), sk, 0); + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id); + r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ ai }), empty_attachment, tx_0, tx_version, tx_hardfork_id, sk, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); if (tx_0.version <= TRANSACTION_VERSION_PRE_HF4) @@ -1166,8 +1168,9 @@ bool gen_alias_too_small_reward::make_tx_reg_alias(std::vector destinations.push_back(tx_destination_entry(sources_amount - (alias_reward + TESTS_DEFAULT_FEE), miner_acc.get_public_address())); // change crypto::secret_key stub = AUTO_VAL_INIT(stub); - uint64_t tx_version = get_tx_version(get_block_height(prev_block), m_hardforks); - r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx, tx_version, stub, uint64_t(0)); + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_hardfork_id(get_block_height(prev_block), m_hardforks, tx_hardfork_id); + r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx, tx_version, tx_hardfork_id, stub, uint64_t(0)); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); PRINT_EVENT_N_TEXT(events, "make_tx_reg_alias -> construct_tx()"); events.push_back(tx); @@ -1317,7 +1320,7 @@ bool gen_alias_switch_and_check_block_template::add_block_from_template(currency bool r = c.get_block_template(b, acc.get_public_address(), acc.get_public_address(), diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); - r = miner::find_nonce_for_given_block(b, diff, height); + r = find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); @@ -1382,8 +1385,9 @@ bool gen_alias_too_many_regs_in_block_template::generate(std::vector& events) } transaction tx{}; - uint64_t tx_version = currency::get_tx_version(get_block_height(blk_0r) + 1, generator.get_hardforks()); + size_t tx_hardfork_id{}; + uint64_t tx_version = currency::get_tx_version_and_hardfork_id(get_block_height(blk_0r) + 1, generator.get_hardforks(), tx_hardfork_id); crypto::secret_key sk{}; - r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ ai }), empty_attachment, tx, tx_version, sk, 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ ai }), empty_attachment, tx, tx_version, tx_hardfork_id, sk, 0); /*tx_builder tb; tb.step1_init(); diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index e2890f37..ed290387 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023 Zano Project +// Copyright (c) 2014-2025 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 @@ -321,10 +321,9 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector& events destinations.push_back(de); transaction tmp_tx; - std::vector attachments; uint64_t tx_version = get_tx_version(get_block_height(blk_0r), m_hardforks); - if (!construct_tx(miner_account.get_keys(), sources, destinations, attachments, tmp_tx, tx_version, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, empty_extra, empty_attachment, tmp_tx, tx_version)) return false; MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); @@ -369,9 +368,8 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector destinations.push_back(de); transaction tmp_tx = AUTO_VAL_INIT(tmp_tx); - std::vector attachments; uint64_t tx_version = get_tx_version(get_block_height(blk_1r), m_hardforks); - if (!construct_tx(miner_account.get_keys(), sources, destinations, attachments, tmp_tx, tx_version, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, empty_extra, empty_attachment, tmp_tx, tx_version)) return false; MAKE_MINER_TX_MANUALLY(miner_tx, blk_1); @@ -692,4 +690,515 @@ bool gen_block_wrong_version_agains_hardfork::generate(std::vector& events) const +{ + // Test idea: make sure that a block with correct previous block identifier that is at the wrong height won't be accepted by the core. + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + + DO_CALLBACK(events, "configure_core"); + + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + MAKE_TX(events, tx_0, miner, miner, MK_TEST_COINS(2), blk_0r); + MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner); + block blk_2{}; + + blk_2.prev_id = currency::get_block_hash(blk_1); + blk_2.miner_tx = blk_0r.miner_tx; + blk_2.major_version = blk_0r.major_version; + CHECK_AND_ASSERT_EQ(currency::get_block_height(blk_1), 11); + CHECK_AND_ASSERT_EQ(currency::get_block_height(blk_2), 10); + // blk_1 is the previous for blk_2, but height(blk_2) < height(blk_1). + DO_CALLBACK_PARAMS_STR(events, "assert_blk_2_has_wrong_height", t_serializable_object_to_blob(blk_2)); + + return true; +} + +bool block_with_correct_prev_id_on_wrong_height::assert_blk_2_has_wrong_height(currency::core& c, [[maybe_unused]] size_t ev_index, [[maybe_unused]] const std::vector& events) const +{ + block blk_2{}; + + { + const auto serialized_block{boost::get(events.at(ev_index)).callback_params}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(blk_2, serialized_block), true); + } + + { + currency::block_verification_context context_blk_2{}; + + CHECK_AND_ASSERT_EQ(boost::get(blk_2.miner_tx.vin.front()).height, 10); + // Make sure, that it's impossible to insert blk_2. + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().add_new_block(blk_2, context_blk_2), false); + } + + return true; +} + +struct block_reward_in_main_chain_basic::argument_assert +{ + uint64_t m_height{}, m_balance{}; + std::list m_rewards{}; + + argument_assert() = default; + + template + argument_assert(const test* instance, uint64_t height, const std::list& blk_tx_fees = {}, const argument_assert previous = {}) : m_height{height} + { + CHECK_AND_ASSERT_THROW(instance, std::runtime_error{"Pointer to an instance of the test equals to the nullptr."}); + CHECK_AND_ASSERT_THROW(m_height >= previous.m_height, std::runtime_error{"A height specified in the previous argument is greather than current height."}); + + if (height == 0) + { + m_rewards.push_back(PREMINE_AMOUNT); + m_balance = m_rewards.back(); + } + + else + { + m_balance = previous.m_balance; + + for (auto fee_iterator{blk_tx_fees.rbegin()}; fee_iterator != blk_tx_fees.rend(); ++fee_iterator) + { + if (height != 0) + { + m_rewards.push_back(COIN); + + if (const auto& fee{*fee_iterator}; fee <= m_rewards.back()) + { + if (instance->m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, height)) + { + m_rewards.back() -= fee; + } + } + + m_balance += m_rewards.back(); + } + + else + { + m_balance += PREMINE_AMOUNT; + } + + --height; + } + } + + CHECK_AND_ASSERT_THROW(m_rewards.size() > 0, std::runtime_error{"A list of the rewards is empty."}); + } + + BEGIN_SERIALIZE() + FIELD(m_height) + FIELD(m_balance) + FIELD(m_rewards) + END_SERIALIZE() +}; + +block_reward_in_main_chain_basic::block_reward_in_main_chain_basic() +{ + REGISTER_CALLBACK_METHOD(block_reward_in_main_chain_basic, assert_balance); + REGISTER_CALLBACK_METHOD(block_reward_in_main_chain_basic, assert_reward); +} + +bool block_reward_in_main_chain_basic::generate(std::vector& events) const +{ + // The test idea: make sure that receiving rewards for block insertion is counted correctly. + + const auto assert_balance{[&events](const argument_assert& argument) -> void + { + DO_CALLBACK_PARAMS_STR(events, "assert_balance", t_serializable_object_to_blob(argument)); + } + }; + + const auto assert_reward{[&events](const argument_assert& argument) -> void + { + DO_CALLBACK_PARAMS_STR(events, "assert_reward", t_serializable_object_to_blob(argument)); + } + }; + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + argument_assert argument{this, get_block_height(blk_0)}; + + m_accounts.push_back(miner); + assert_reward(argument); + // Make sure the balance equals to the PREMINE_AMOUNT. + assert_balance(argument); + DO_CALLBACK(events, "configure_core"); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + + argument = argument_assert{this, get_block_height(blk_1), {0}, argument}; + assert_balance(argument); + assert_reward(argument); + + REWIND_BLOCKS_N(events, blk_1r, blk_1, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1); + + argument = argument_assert{this, get_block_height(blk_1r), std::list(CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1), argument}; + assert_balance(argument); + assert_reward(argument); + + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, blk_1r); + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner, tx_0); + + argument = {this, get_block_height(blk_2), {TESTS_DEFAULT_FEE}, argument}; + assert_reward(argument); + // Make sure in the balance change in the case of a transaction with the default fee. + assert_balance(argument); + + MAKE_TX_FEE(events, tx_1, miner, miner, MK_TEST_COINS(3), 2 * TESTS_DEFAULT_FEE, blk_2); + MAKE_TX_FEE(events, tx_2, miner, miner, MK_TEST_COINS(2), 3 * TESTS_DEFAULT_FEE, blk_2); + + const std::list txs{tx_1, tx_2}; + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2, miner, txs); + + argument = argument_assert{this, get_block_height(blk_3), {(2 + 3) * TESTS_DEFAULT_FEE}, argument}; + assert_reward(argument); + // A case of one inserted block with a several transactions with a non default fees. + assert_balance(argument); + + MAKE_TX_FEE(events, tx_3, miner, miner, MK_TEST_COINS(1), COIN + TESTS_DEFAULT_FEE, blk_3); + MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner); + + argument = argument_assert{this, get_block_height(blk_4), {COIN + TESTS_DEFAULT_FEE}, argument}; + assert_reward(argument); + // A transaction inside blk_4 has a fee greater than a block reward. blk_4 includes only one transaction. + assert_balance(argument); + + MAKE_TX_FEE(events, tx_4, miner, miner, MK_TEST_COINS(1), 76 * COIN + 14 * TESTS_DEFAULT_FEE, blk_4); + MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner); + + argument = argument_assert{this, get_block_height(blk_5), {76 * COIN + 14 * TESTS_DEFAULT_FEE}, argument}; + assert_reward(argument); + // A transaction inside blk_5 has a fee greater than a block reward. blk_5 includes only one transaction. + assert_balance(argument); + + REWIND_BLOCKS_N(events, blk_5r, blk_5, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + argument = argument_assert{this, get_block_height(blk_5r), std::list(CURRENCY_MINED_MONEY_UNLOCK_WINDOW), argument}; + assert_reward(argument); + assert_balance(argument); + + return true; +} + +bool block_reward_in_main_chain_basic::assert_balance(currency::core& core, size_t event_index, const std::vector& events) const +{ + argument_assert argument{}; + + { + const auto serialized_argument{boost::get(events.at(event_index)).callback_params}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(argument, serialized_argument), true); + } + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_top_block_height(), argument.m_height); + + const auto wallet{init_playtime_test_wallet(events, core, m_accounts.front())}; + + CHECK_AND_ASSERT(wallet, false); + wallet->refresh(); + CHECK_AND_ASSERT_EQ(wallet->balance(), argument.m_balance); + + return true; +} + +bool block_reward_in_main_chain_basic::assert_reward(currency::core& core, size_t event_index, const std::vector& events) const +{ + argument_assert argument{}; + + { + const auto serialized_argument{boost::get(events.at(event_index)).callback_params}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(argument, serialized_argument), true); + } + + for (const auto expected_reward : argument.m_rewards) + { + uint64_t reward{}; + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_block_reward_by_main_chain_height(argument.m_height, reward), true); + CHECK_AND_ASSERT_EQ(reward, expected_reward); + --argument.m_height; + } + + return true; +} + +struct block_reward_in_alt_chain_basic::argument_assert +{ + uint64_t m_height{}, m_balance{}; + crypto::hash blk_id{}; + std::list m_rewards{}; + + argument_assert() = default; + + template + argument_assert(const test* instance, const block& block, const std::list& blk_tx_fees = {}, const argument_assert previous = {}) : blk_id{get_block_hash(block)} + { + CHECK_AND_ASSERT_THROW(instance, std::runtime_error{"Pointer to an instance of the test equals to the nullptr."}); + + auto height{get_block_height(block)}; + + m_height = height; + + if (height == 0) + { + m_rewards.push_back(PREMINE_AMOUNT); + m_balance = m_rewards.back(); + return; + } + + m_balance = previous.m_balance; + + for (auto fee_iterator{blk_tx_fees.rbegin()}; fee_iterator != blk_tx_fees.rend(); ++fee_iterator) + { + if (height != 0) + { + m_rewards.push_back(COIN); + + if (const auto& fee{*fee_iterator}; fee <= m_rewards.back()) + { + if (instance->m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, height)) + { + m_rewards.back() -= fee; + } + } + + m_balance += m_rewards.back(); + } + + else + { + m_balance += PREMINE_AMOUNT; + } + + --height; + } + + CHECK_AND_ASSERT_THROW(m_rewards.size() > 0, std::runtime_error{"A list of the rewards is empty."}); + } + + BEGIN_SERIALIZE() + FIELD(m_height) + FIELD(m_balance) + FIELD(m_rewards) + FIELD(blk_id) + END_SERIALIZE() +}; + +block_reward_in_alt_chain_basic::block_reward_in_alt_chain_basic() +{ + REGISTER_CALLBACK_METHOD(block_reward_in_alt_chain_basic, assert_balance); + REGISTER_CALLBACK_METHOD(block_reward_in_alt_chain_basic, assert_reward); +} + +bool block_reward_in_alt_chain_basic::generate(std::vector& events) const +{ + // The test idea: make sure that receiving rewards for block insertion is counted correctly. + + const auto assert_balance{[&events](const argument_assert& argument) -> void + { + DO_CALLBACK_PARAMS_STR(events, "assert_balance", t_serializable_object_to_blob(argument)); + } + }; + + const auto assert_reward{[&events](const argument_assert& argument) -> void + { + DO_CALLBACK_PARAMS_STR(events, "assert_reward", t_serializable_object_to_blob(argument)); + } + }; + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + argument_assert argument{this, blk_0}, argument_alt{}; + + /* 0 + (blk_0) */ + + m_accounts.push_back(miner); + // Make sure a reward for the blk_0 equals to PREMINE_AMOUNT. + assert_reward(argument); + // Make sure the balance equals to the PREMINE_AMOUNT. + assert_balance(argument); + DO_CALLBACK(events, "configure_core"); + + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + /* 0 10 + (blk_0) - ... - (blk_0r) */ + + // A case of a 10 sequentally inserted empty sblocks. + argument_alt = argument = argument_assert{this, blk_0r, std::list(CURRENCY_MINED_MONEY_UNLOCK_WINDOW), argument}; + // Miner inserted 10 empty blocks. A sum of the rewards for them equals to 10 coins. + assert_reward(argument); + // Make sure the balance equals to PREMINE_AMOUNT + 10 * COIN. + assert_balance(argument); + + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, blk_0r); + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner, tx_0); + + /* 0 10 11 + (blk_0) - ... - (blk_0r) - (blk_1) + {tx_0} */ + + MAKE_TX_FEE(events, tx_1, miner, miner, MK_TEST_COINS(1), 33 * TESTS_DEFAULT_FEE, blk_0r); + MAKE_NEXT_BLOCK_TX1(events, blk_1a, blk_0r, miner, tx_1); + + /* 0 10 11 + (blk_0) - ... - (blk_0r) - (blk_1a) + | {tx_1} + | + \ 11 + - (blk_1) + {tx_0} + + height(blk_1a) = height(blk_1) + fee(tx_1) > fee(tx_0). */ + + CHECK_AND_ASSERT_EQ(get_block_height(blk_1), get_block_height(blk_1a)); + + // Case of an alt block on the height 11 with greater total fee than total fee of blk_1 - the top of the main chain. + argument_alt = argument_assert{this, blk_1a, {33 * TESTS_DEFAULT_FEE}, argument_alt}; + argument = argument_assert{this, blk_1, {TESTS_DEFAULT_FEE}, argument}; + + if (m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, get_block_height(blk_1))) + { + // Make sure that a reward for blk_1 equals to COIN. + assert_reward(argument_alt); + // Make sure that the balance equals to PREMINE_AMOUNT + 11 * COIN - 33 * TESTS_DEFAULT_FEE. + assert_balance(argument_alt); + } + + else + { + // Make sure that a reward for blk_1a equals to COIN. + assert_reward(argument); + // Make sure that the balance equals to PREMINE_AMOUNT + 11 * COIN. + assert_balance(argument); + } + + MAKE_TX_FEE(events, tx_2, miner, miner, MK_TEST_COINS(1), 8 * TESTS_DEFAULT_FEE, blk_1); + MAKE_TX_FEE(events, tx_3, miner, miner, MK_TEST_COINS(1), 57 * TESTS_DEFAULT_FEE, blk_1); + const std::list txs_0{tx_2, tx_3}; + + MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1, miner, txs_0); + + /* 0 10 11 12 + (blk_0) - ... - (blk_0r) - (blk_1) - (blk_2) + | {tx_0} {tx_2, tx_3} + | + \ 11 + - (blk_1a) + {tx_1} + + height(blk_2) > height(blk_1a). */ + + // A case of block on the height 12 in the main chain. + argument = argument_assert{this, blk_2, {(8 + 57) * TESTS_DEFAULT_FEE}, argument}; + // A reward of blk_2 equals to coin. + assert_reward(argument); + /* HF3: The balance equals to PREMINE_AMOUNT + 12 * COIN. + HF4: The balance equals to PREMINE_AMOUNT + 12 * COIN - 65 * TESTS_DEFAULT_FEE. */ + assert_balance(argument); + + const auto& head_blk_for_txs_on_height_12{m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, get_block_height(blk_2)) ? blk_1a : blk_0r}; + MAKE_TX_FEE(events, tx_4, miner, miner, MK_TEST_COINS(2), 15 * TESTS_DEFAULT_FEE, head_blk_for_txs_on_height_12); + MAKE_TX_FEE(events, tx_5, miner, miner, MK_TEST_COINS(5), 29 * TESTS_DEFAULT_FEE, head_blk_for_txs_on_height_12); + MAKE_TX_FEE(events, tx_6, miner, miner, MK_TEST_COINS(7), 22 * TESTS_DEFAULT_FEE, head_blk_for_txs_on_height_12); + const std::list txs_1{tx_4, tx_5, tx_6}; + MAKE_NEXT_BLOCK_TX_LIST(events, blk_2a, blk_1a, miner, txs_1); + + CHECK_AND_ASSERT_EQ(get_block_height(blk_2a), get_block_height(blk_2)); + + /* 0 10 11 12 + (blk_0) - ... - (blk_0r) - (blk_1a) - (blk_2a) + | {tx_1} {tx_4, tx_5, tx_6} + | + \ 11 12 + - (blk_1) - (blk_2) + {tx_0} {tx_2, tx_3} + + height(blk_2a) = height(blk_2) = 12 + fee(tx_2) + fee(tx_3) = (8 + 57) * TESTS_DEFAULT_FEE = 65 * TESTS_DEFAULT_FEE + fee(tx_4) + fee(tx_5) + fee(tx_6) = (15 + 29 + 22) * TESTS_DEFAULT_FEE = 66 * TESTS_DEFAULT_FEE + 66 > 65. */ + + if (m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, get_block_height(blk_2))) + { + // Case of an alt block on the height 12 with greater total fee than total fee of blk_2 - the top of the main chain. + argument_alt = argument_assert{this, blk_2a, {(15 + 29 + 22) * TESTS_DEFAULT_FEE}, argument_alt}; + // Make sure a reward for blk_2a is equals to COIN. + assert_reward(argument_alt); + // Make sure the balance equals to PREMINE_AMOUNT + 12 * COIN - 99 * TESTS_DEFAULT_FEE. + assert_balance(argument_alt); + } + + else + { + // Make sure a reward for blk_2 is equals to COIN. + assert_reward(argument); + // Make sure the balance equals to PREMINE_AMOUNT + 12 * COIN. + assert_balance(argument); + } + + return true; +} + +bool block_reward_in_alt_chain_basic::assert_balance(currency::core& core, size_t event_index, const std::vector& events) const +{ + argument_assert argument{}; + + { + const auto serialized_argument{boost::get(events.at(event_index)).callback_params}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(argument, serialized_argument), true); + } + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_top_block_height(), argument.m_height); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_top_block_id(), argument.blk_id); + + const auto wallet{init_playtime_test_wallet(events, core, m_accounts.front())}; + + CHECK_AND_ASSERT(wallet, false); + wallet->refresh(); + CHECK_AND_ASSERT_EQ(wallet->balance(), argument.m_balance); + + return true; +} + +bool block_reward_in_alt_chain_basic::assert_reward(currency::core& core, size_t event_index, const std::vector& events) const +{ + argument_assert argument{}; + + { + const auto serialized_argument{boost::get(events.at(event_index)).callback_params}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(argument, serialized_argument), true); + } + + { + auto blk_id{argument.blk_id}; + + for (const auto expected_reward : argument.m_rewards) + { + uint64_t reward{}; + block blk{}; + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_block_reward_by_hash(blk_id, reward), true); + CHECK_AND_ASSERT_EQ(reward, expected_reward); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().get_block_by_hash(blk_id, blk), true); + blk_id = blk.prev_id; + } + } + + return true; +} diff --git a/tests/core_tests/block_validation.h b/tests/core_tests/block_validation.h index f21463ca..59e4c149 100644 --- a/tests/core_tests/block_validation.h +++ b/tests/core_tests/block_validation.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023 Zano Project +// Copyright (c) 2014-2025 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 @@ -6,6 +6,7 @@ #pragma once #include "chaingen.h" +#include "wallet_tests_basic.h" template class gen_block_verification_base : public test_chain_unit_enchanced @@ -187,3 +188,32 @@ struct gen_block_invalid_binary_format : public test_chain_unit_base private: size_t m_corrupt_blocks_begin_idx; }; + +struct block_with_correct_prev_id_on_wrong_height : public gen_block_verification_base<1 + CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3> +{ + block_with_correct_prev_id_on_wrong_height(); + bool generate(std::vector& events) const; + bool assert_blk_2_has_wrong_height(currency::core& c, size_t ev_index, const std::vector& events) const; +}; + +struct block_reward_in_main_chain_basic : wallet_test +{ + block_reward_in_main_chain_basic(); + bool generate(std::vector& events) const; + +private: + bool assert_balance(currency::core& core, size_t event_index, const std::vector& events) const; + bool assert_reward(currency::core& core, size_t event_index, const std::vector& events) const; + struct argument_assert; +}; + +struct block_reward_in_alt_chain_basic : wallet_test +{ + block_reward_in_alt_chain_basic(); + bool generate(std::vector& events) const; + +private: + bool assert_balance(currency::core& core, size_t event_index, const std::vector& events) const; + bool assert_reward(currency::core& core, size_t event_index, const std::vector& events) const; + struct argument_assert; +}; diff --git a/tests/core_tests/chain_switch_1.cpp b/tests/core_tests/chain_switch_1.cpp index 69ad2a28..b607e852 100644 --- a/tests/core_tests/chain_switch_1.cpp +++ b/tests/core_tests/chain_switch_1.cpp @@ -532,9 +532,10 @@ bool alt_blocks_validation_and_same_new_amount_in_two_txs::generate(std::vector< std::vector destinations; destinations.push_back(tx_destination_entry(new_amount, miner_acc.get_public_address())); destinations.push_back(tx_destination_entry(TESTS_DEFAULT_FEE, miner_acc.get_public_address())); //just to make two outputs (to please HF4 rules) - transaction tx_1 = AUTO_VAL_INIT(tx_1); - uint64_t tx_version = get_tx_version(get_block_height(blk_3), m_hardforks); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, tx_version, 0); + transaction tx_1{}; + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_3), m_hardforks, tx_hardfork_id); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, tx_version, tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); ADD_CUSTOM_EVENT(events, tx_1); @@ -544,8 +545,8 @@ bool alt_blocks_validation_and_same_new_amount_in_two_txs::generate(std::vector< CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); transaction tx_2 = AUTO_VAL_INIT(tx_2); // use the same destinations - tx_version = get_tx_version(get_block_height(blk_3), m_hardforks); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_2, tx_version, 0); + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_3), m_hardforks, tx_hardfork_id); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_2, tx_version, tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); ADD_CUSTOM_EVENT(events, tx_2); @@ -913,16 +914,10 @@ bool alt_chain_and_block_tx_fee_median::generate( CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); - tx_version = get_tx_version(get_block_height(blk_1r), - m_hardforks); + size_t tx_hardfork_id{}; + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_1r), m_hardforks, tx_hardfork_id); - success = construct_tx(miner.get_keys(), - sources, - destinations, - empty_attachment, - tx_0, - tx_version, - 0); + success = construct_tx(miner.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version, tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_0"); @@ -934,8 +929,7 @@ bool alt_chain_and_block_tx_fee_median::generate( // Transaction tx_1 is constructed and placed in block blk_2a. - tx_version = get_tx_version(get_block_height(blk_1r), - m_hardforks); + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_1r), m_hardforks, tx_hardfork_id); success = fill_tx_sources_and_destinations( events, @@ -950,13 +944,7 @@ bool alt_chain_and_block_tx_fee_median::generate( CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); - success = construct_tx(miner.get_keys(), - sources, - destinations, - empty_attachment, - tx_1, - tx_version, - 0); + success = construct_tx(miner.get_keys(), sources, destinations, empty_attachment, tx_1, tx_version, tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_1"); diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 2679dd39..7fb1787a 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -299,6 +299,8 @@ bool test_generator::construct_block(currency::block& blk, tx_generation_context miner_tx_tgc{}; uint64_t block_reward_without_fee = 0; uint64_t block_reward = 0; + size_t tx_hardfork_id = 0; + uint64_t tx_version = get_tx_version_and_hardfork_id(height, m_hardforks, tx_hardfork_id); while (true) { r = construct_miner_tx(height, misc_utils::median(block_sizes), @@ -310,7 +312,8 @@ bool test_generator::construct_block(currency::block& blk, blk.miner_tx, block_reward_without_fee, block_reward, - get_tx_version(height, m_hardforks), + tx_version, + tx_hardfork_id, blobdata(), test_generator::get_test_gentime_settings().miner_tx_max_outs, static_cast(coin_stake_sources.size()), @@ -836,7 +839,7 @@ bool test_generator::find_nounce(currency::block& blk, std::vector& event void fill_nonce(currency::block& blk, const wide_difficulty_type& diffic, uint64_t height) { blk.nonce = 0; - while (!miner::find_nonce_for_given_block(blk, diffic, height)) + while (!find_nonce_for_given_block(blk, diffic, height)) blk.timestamp++; }*/ @@ -1745,8 +1750,9 @@ bool construct_tx_to_key(const currency::hard_forks_descriptor& hf, std::vector destinations; if (!fill_tx_sources_and_destinations(events, blk_head, from.get_keys(), to.get_public_address(), amount, fee, nmix, sources, destinations, check_for_spends, check_for_unlocktime)) return false; - uint64_t tx_version = currency::get_tx_version(get_block_height(blk_head) + 1, hf); // assuming the tx will be in the next block (blk_head + 1) - return construct_tx(from.get_keys(), sources, destinations, extr, att, tx, tx_version, sk, 0, mix_attr); + size_t tx_hardfork_id = 0; + uint64_t tx_version = currency::get_tx_version_and_hardfork_id(get_block_height(blk_head) + 1, hf, tx_hardfork_id); // assuming the tx will be in the next block (blk_head + 1) + return construct_tx(from.get_keys(), sources, destinations, extr, att, tx, tx_version, tx_hardfork_id, sk, 0, mix_attr); } bool construct_tx_to_key(const currency::hard_forks_descriptor& hf, @@ -1774,16 +1780,17 @@ bool construct_tx_to_key(const currency::hard_forks_descriptor& hf, return false; uint64_t tx_expected_block_height = get_block_height(blk_head) + 1; - uint64_t tx_version = currency::get_tx_version(tx_expected_block_height, hf); + size_t tx_hardfork_id = 0; + uint64_t tx_version = currency::get_tx_version_and_hardfork_id(tx_expected_block_height, hf, tx_hardfork_id); boost::multiprecision::int128_t change = get_sources_total_amount(sources); change -= spending_amount; if (change < 0) return false; // should never happen if fill_tx_sources succeded if (change == 0) - return construct_tx(from.get_keys(), sources, destinations, extr, att, tx, tx_version, sk, 0, mix_attr); + return construct_tx(from.get_keys(), sources, destinations, extr, att, tx, tx_version, tx_hardfork_id, sk, 0, mix_attr); std::vector local_dst = destinations; local_dst.push_back(tx_destination_entry(change.convert_to(), from.get_public_address())); - return construct_tx(from.get_keys(), sources, local_dst, extr, att, tx, tx_version, sk, 0, mix_attr); + return construct_tx(from.get_keys(), sources, local_dst, extr, att, tx, tx_version, tx_hardfork_id, sk, 0, mix_attr); } @@ -1812,8 +1819,53 @@ bool construct_tx_with_many_outputs(const currency::hard_forks_descriptor& hf, s uint64_t sources_amount = get_sources_total_amount(sources); if (sources_amount > total_amount + fee) destinations.push_back(tx_destination_entry(sources_amount - (total_amount + fee), keys_from.account_address)); // change - uint64_t tx_version = currency::get_tx_version(currency::get_block_height(blk_head), hf); - return construct_tx(keys_from, sources, destinations, empty_attachment, tx, tx_version, 0); + size_t tx_hardfork_id = 0; + uint64_t tx_version = currency::get_tx_version_and_hardfork_id(currency::get_block_height(blk_head), hf, tx_hardfork_id); + return construct_tx(keys_from, sources, destinations, empty_attachment, tx, tx_version, tx_hardfork_id, 0); +} + +bool construct_tx(const account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + transaction& tx, + uint64_t tx_version, + size_t tx_hardfork_id, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + uint64_t expiration_time, + uint8_t tx_outs_attr, + bool shuffle, + uint64_t flags, + uint64_t explicit_consolidated_tx_fee, + tx_generation_context& gen_context) +{ + // extra copy operation, but creating transaction is not sensitive to this + finalize_tx_param ftp {}; + ftp.tx_version = tx_version; + ftp.tx_hardfork_id = tx_hardfork_id; + ftp.sources = sources; + ftp.prepared_destinations = destinations; + ftp.extra = extra; + ftp.attachments = attachments; + ftp.unlock_time = unlock_time; + // ftp.crypt_address = crypt_destination_addr; + ftp.expiration_time = expiration_time; + ftp.tx_outs_attr = tx_outs_attr; + ftp.shuffle = shuffle; + ftp.flags = flags; + ftp.mode_separate_fee = explicit_consolidated_tx_fee; + + finalized_tx ft{}; + ft.tx = tx; + ft.one_time_key = one_time_secret_key; + ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle + bool r = construct_tx(sender_account_keys, ftp, ft); + tx = ft.tx; + one_time_secret_key = ft.one_time_key; + gen_context = ft.ftp.gen_context; + return r; } bool construct_tx(const account_keys& sender_account_keys, @@ -1835,6 +1887,9 @@ bool construct_tx(const account_keys& sender_account_keys, // extra copy operation, but creating transaction is not sensitive to this finalize_tx_param ftp {}; ftp.tx_version = tx_version; + if (tx_version >= TRANSACTION_VERSION_POST_HF5) + LOG_PRINT_YELLOW("warning: tx_hardfork_id not set for tx, while it seems to be HF5", LOG_LEVEL_0); + ftp.tx_hardfork_id = 0; ftp.sources = sources; ftp.prepared_destinations = destinations; ftp.extra = extra; @@ -1847,7 +1902,7 @@ bool construct_tx(const account_keys& sender_account_keys, ftp.flags = flags; ftp.mode_separate_fee = explicit_consolidated_tx_fee; - finalized_tx ft = AUTO_VAL_INIT(ft); + finalized_tx ft{}; ft.tx = tx; ft.one_time_key = one_time_secret_key; ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle @@ -1858,6 +1913,63 @@ bool construct_tx(const account_keys& sender_account_keys, return r; } +bool construct_tx(const currency::account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + currency::transaction& tx, + uint64_t tx_version, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time) +{ + [[maybe_unused]] tx_generation_context gen_context{}; + return construct_tx(sender_account_keys, + sources, + destinations, + extra, + attachments, + tx, + tx_version, + one_time_secret_key, + unlock_time, + 0, /* expiration_time */ + CURRENCY_TO_KEY_OUT_RELAXED, /* tx_outs_attr */ + true, /* shuffle */ + 0, /* flags */ + 0, /* explicit_consolidated_tx_fee */ + gen_context /* tx_generation_context */ + ); +} + +bool construct_tx(const currency::account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + currency::transaction& tx, + uint64_t tx_version) +{ + [[maybe_unused]] tx_generation_context gen_context{}; + [[maybe_unused]] crypto::secret_key tx_sec_key{}; + return construct_tx(sender_account_keys, + sources, + destinations, + extra, + attachments, + tx, + tx_version, + tx_sec_key, /* one_time_secret_key */ + 0, /* unlock_time */ + 0, /* expiration_time */ + CURRENCY_TO_KEY_OUT_RELAXED, /* tx_outs_attr */ + true, /* shuffle */ + 0, /* flags */ + 0, /* explicit_consolidated_tx_fee */ + gen_context /* tx_generation_context */ + ); +} + uint64_t get_balance(const currency::account_keys& addr, const std::vector& blockchain, const map_hash2tx_t& mtx, bool dbg_log) { uint64_t res = 0; @@ -2560,19 +2672,26 @@ void test_chain_unit_base::register_callback(const std::string& cb_name, verify_ m_callbacks[cb_name] = cb; } -uint64_t test_chain_unit_base::get_tx_version_from_events(const std::vector &events)const +uint64_t test_chain_unit_base::get_tx_version_from_events(const std::vector &events) const +{ + [[maybe_unused]] size_t tx_hardfork_id{}; + return get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id); +} + +uint64_t test_chain_unit_base::get_tx_version_and_harfork_id_from_events(const std::vector &events, size_t& tx_hardfork_id) const { for (auto it = events.rbegin(); it!= events.rend(); it++) { if(it->type() == typeid(currency::block)) { const currency::block& b = boost::get(*it); - return currency::get_tx_version(get_block_height(b), m_hardforks); + return currency::get_tx_version_and_hardfork_id(get_block_height(b), m_hardforks, tx_hardfork_id); } } - return currency::get_tx_version(0, m_hardforks); + return currency::get_tx_version_and_hardfork_id(0, m_hardforks, tx_hardfork_id); } + bool test_chain_unit_base::verify(const std::string& cb_name, currency::core& c, size_t ev_index, const std::vector &events) { auto cb_it = m_callbacks.find(cb_name); diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 1ff60a9a..f81efb4f 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -257,6 +257,7 @@ public: bool need_core_proxy() const { return false; } // tests can override this in order to obtain core proxy (e.g. for wallet) void set_core_proxy(std::shared_ptr) { /* do nothing */ } uint64_t get_tx_version_from_events(const std::vector &events) const; + uint64_t get_tx_version_and_harfork_id_from_events(const std::vector &events, size_t& tx_hardfork_id) const; virtual void on_test_constructed() {} // called right after test class is constructed by the chaingen void on_test_generator_created(test_generator& generator) const; // tests can override this for special initialization @@ -691,6 +692,41 @@ bool construct_tx(const currency::account_keys& sender_account_keys, uint64_t explicit_consolidated_tx_fee, currency::tx_generation_context& gen_context); +bool construct_tx(const currency::account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + currency::transaction& tx, + uint64_t tx_version, + size_t tx_hardfork_id, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time, + uint64_t expiration_time, + uint8_t tx_outs_attr, + bool shuffle, + uint64_t flags, + uint64_t explicit_consolidated_tx_fee, + currency::tx_generation_context& gen_context); + +bool construct_tx(const currency::account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + currency::transaction& tx, + uint64_t tx_version, + crypto::secret_key& one_time_secret_key, + uint64_t unlock_time); + +bool construct_tx(const currency::account_keys& sender_account_keys, + const std::vector& sources, + const std::vector& destinations, + const std::vector& extra, + const std::vector& attachments, + currency::transaction& tx, + uint64_t tx_version); + void get_confirmed_txs(const std::vector& blockchain, const map_hash2tx_t& mtx, map_hash2tx_t& confirmed_txs); bool find_block_chain(const std::vector& events, std::vector& blockchain, map_hash2tx_t& mtx, const crypto::hash& head); bool fill_tx_sources(std::vector& sources, const std::vector& events, @@ -994,10 +1030,12 @@ bool test_generator::construct_block_gentime_with_coinbase_cb(const currency::bl uint64_t block_reward_without_fee = 0; uint64_t block_reward = 0; + size_t tx_hardfork_id = 0; + uint64_t tx_version = get_tx_version_and_hardfork_id(height, m_hardforks, tx_hardfork_id); currency::keypair tx_sec_key = currency::keypair::generate(); r = construct_miner_tx(height, epee::misc_utils::median(block_sizes), already_generated_coins, 0 /* current_block_size !HACK! */, 0, - acc.get_public_address(), acc.get_public_address(), miner_tx, block_reward_without_fee, block_reward, get_tx_version(height, m_hardforks), currency::blobdata(), /* max outs: */ 1, + acc.get_public_address(), acc.get_public_address(), miner_tx, block_reward_without_fee, block_reward, tx_version, tx_hardfork_id, currency::blobdata(), /* max outs: */ 1, /* pos: */ false, currency::pos_entry(), /* ogc_ptr: */ nullptr, &tx_sec_key); CHECK_AND_ASSERT_MES(r, false, "construct_miner_tx failed"); diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index 703aec6f..15d954a7 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.h @@ -33,7 +33,7 @@ inline bool mine_next_pow_block_in_playtime(const currency::account_public_addre test_core_time::adjust(b.timestamp); modify_block_cb(b); - r = currency::miner::find_nonce_for_given_block(b, cbtr.diffic, cbtr.height); + r = currency::find_nonce_for_given_block(b, cbtr.diffic, cbtr.height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc{}; @@ -119,7 +119,7 @@ inline bool mine_next_pow_block_in_playtime_with_given_txs(const currency::accou height = cbtr.height; } - r = currency::miner::find_nonce_for_given_block(b, cbtr.diffic, cbtr.height); + r = currency::find_nonce_for_given_block(b, cbtr.diffic, cbtr.height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc{}; @@ -313,9 +313,10 @@ inline bool put_alias_via_tx_to_list(const currency::hard_forks_descriptor& hf, el.flags |= currency::tx_destination_entry_flags::tdef_explicit_native_asset_id | currency::tx_destination_entry_flags::tdef_zero_amount_blinding_mask; // all alias-burn outputs must have explicit native asset id and zero amount mask } - uint64_t tx_version = currency::get_tx_version(get_block_height(head_block) + 1, generator.get_hardforks()); // assuming the tx will be in the next block (head_block + 1) + size_t tx_hardfork_id{}; + uint64_t tx_version = currency::get_tx_version_and_hardfork_id(get_block_height(head_block) + 1, generator.get_hardforks(), tx_hardfork_id); // assuming the tx will be in the next block (head_block + 1) tx_set.emplace_back(); - r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_set.back(), tx_version, generator.last_tx_generated_secret_key, 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, extra, empty_attachment, tx_set.back(), tx_version, tx_hardfork_id, generator.last_tx_generated_secret_key, 0); PRINT_EVENT_N_TEXT(events, "put_alias_via_tx_to_list()"); events.push_back(tx_set.back()); diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index d1a217c6..11856db7 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -387,7 +387,7 @@ bool gen_and_play_intermitted_by_blockchain_saveload(const char* const genclass_ #define GENERATE_AND_PLAY(genclass) \ - if (!skip_all_till_the_end && ((!postponed_tests.count(#genclass) && run_single_test.empty()) || (!run_single_test.empty() && std::string::npos != std::string(#genclass).find(run_single_test)))) \ + if (!skip_all_till_the_end && ((!postponed_tests.count(#genclass) && run_single_test.empty()) || (!run_single_test.empty() && std::string(#genclass) == run_single_test))) \ { \ TIME_MEASURE_START_MS(t); \ ++tests_count; \ @@ -422,7 +422,7 @@ bool gen_and_play_intermitted_by_blockchain_saveload(const char* const genclass_ } #define GENERATE_AND_PLAY_HF(genclass, hardfork_str_mask) \ - if (!skip_all_till_the_end && ((!postponed_tests.count(#genclass) && run_single_test.empty()) || (!run_single_test.empty() && std::string::npos != std::string(#genclass).find(run_single_test)))) \ + if (!skip_all_till_the_end && ((!postponed_tests.count(#genclass) && run_single_test.empty()) || (!run_single_test.empty() && std::string(#genclass) == run_single_test))) \ { \ std::vector hardforks = parse_hardfork_str_mask(hardfork_str_mask); \ CHECK_AND_ASSERT_MES(!hardforks.empty(), false, "invalid hardforks mask: " << hardfork_str_mask); \ @@ -1154,6 +1154,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(one_block); GENERATE_AND_PLAY(gen_ring_signature_1); GENERATE_AND_PLAY(gen_ring_signature_2); + GENERATE_AND_PLAY(fill_tx_rpc_inputs); //GENERATE_AND_PLAY(gen_ring_signature_big); // Takes up to XXX hours (if CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10) // tests for outputs mixing in @@ -1177,6 +1178,9 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(gen_block_unlock_time_is_timestamp_in_future, "0,3"); GENERATE_AND_PLAY_HF(gen_block_height_is_low, "0,3"); GENERATE_AND_PLAY_HF(gen_block_height_is_high, "0,3"); + GENERATE_AND_PLAY_HF(block_with_correct_prev_id_on_wrong_height, "3-*"); + GENERATE_AND_PLAY_HF(block_reward_in_main_chain_basic, "3-*"); + GENERATE_AND_PLAY_HF(block_reward_in_alt_chain_basic, "3-*"); GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_2_tx_gen_in, "0,3"); GENERATE_AND_PLAY_HF(gen_block_miner_tx_has_2_in, "0,3"); GENERATE_AND_PLAY_HF(gen_block_miner_tx_with_txin_to_key, "0,3"); @@ -1221,6 +1225,7 @@ int main(int argc, char* argv[]) /* To execute the check of bare balance (function "check_tx_bare_balance") we need to run the test "tx_pool_semantic_validation" on the HF 3. By default behaviour bare outputs are disallowed on the heights >= 10. */ GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3"); + GENERATE_AND_PLAY(input_refers_to_incompatible_by_type_output); // Double spend GENERATE_AND_PLAY(gen_double_spend_in_tx); @@ -1271,6 +1276,9 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(hardfork_4_wallet_sweep_bare_outs); GENERATE_AND_PLAY_HF(hardfork_4_pop_tx_from_global_index, "4-*"); + // HF5 + GENERATE_AND_PLAY_HF(hard_fork_5_tx_version, "5-*"); + // atomics GENERATE_AND_PLAY(atomic_simple_test); GENERATE_AND_PLAY(atomic_test_wrong_redeem_wrong_refund); diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h index abac7b00..f7f84633 100644 --- a/tests/core_tests/chaingen_tests_list.h +++ b/tests/core_tests/chaingen_tests_list.h @@ -39,10 +39,12 @@ #include "hard_fork_1.h" #include "hard_fork_2.h" #include "hard_fork_4.h" +#include "hard_fork_5.h" #include "atomic_tests.h" #include "isolate_auditable_and_proof.h" #include "zarcanum_test.h" #include "multiassets_test.h" #include "ionic_swap_tests.h" #include "attachment_isolation_encryption_test.h" -#include "pos_fuse_test.h" \ No newline at end of file +#include "pos_fuse_test.h" +#include "daemon_rpc.h" diff --git a/tests/core_tests/checkpoints_tests.cpp b/tests/core_tests/checkpoints_tests.cpp index d0b88650..50668524 100644 --- a/tests/core_tests/checkpoints_tests.cpp +++ b/tests/core_tests/checkpoints_tests.cpp @@ -930,8 +930,8 @@ bool gen_checkpoints_and_invalid_tx_to_pool::generate(std::vector& events) const +{ + // Test idea: make sure that the function "blockchain_storage::fill_tx_rpc_inputs" works as expected. + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + + DO_CALLBACK(events, "configure_core"); + + // A transaction in the default state. + DO_CALLBACK_PARAMS_STR(events, "c1", t_serializable_object_to_blob(currency::transaction{})); + + // A transaction with an input of the type "txin_to_key" in the default state. + { + currency::transaction tx{}; + + tx.vin.push_back(std::move(currency::txin_to_key{})); + DO_CALLBACK_PARAMS_STR(events, "c2", t_serializable_object_to_blob(tx)); + } + + // A transaction with an input of the type "txin_zc_input". + { + currency::transaction tx{}; + + { + currency::txin_zc_input input{}; + + input.k_image = {}; + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c3", t_serializable_object_to_blob(tx)); + } + + // A transaction with several "txin_to_key" inputs those have different .amount values. + { + currency::transaction tx{}; + + tx.vin.reserve(3); + + { + currency::txin_to_key input{}; + + CHECK_AND_ASSERT_EQ(input.amount, 0); + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_to_key input{}; + + input.amount = UINT64_MAX; + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_to_key input{}; + + input.amount = 16730018105294876523ull; + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c4", t_serializable_object_to_blob(tx)); + } + + // A transaction with inputs of all possible types. + { + currency::transaction tx{}; + + tx.vin.reserve(5); + tx.vin.push_back(std::move(currency::txin_gen{})); + tx.vin.push_back(std::move(currency::txin_to_key{})); + tx.vin.push_back(std::move(currency::txin_htlc{})); + + { + currency::txin_zc_input input{}; + + input.k_image = {}; + tx.vin.push_back(std::move(input)); + } + + tx.vin.push_back(std::move(currency::txin_multisig{})); + + DO_CALLBACK_PARAMS_STR(events, "c5", t_serializable_object_to_blob(tx)); + } + + REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner, tx_0); + + // A transaction with inputs of all possible types. + { + currency::transaction tx{}; + + tx.vin.reserve(5); + tx.vin.push_back(std::move(currency::txin_gen{/* .height = */ 7137406440025745250})); + + { + currency::txin_to_key input{}; + + input.key_offsets.push_back(5350230927837587142ull); + input.key_offsets.push_back(std::move(currency::ref_by_id{currency::get_transaction_hash(tx_0), 0u})); + input.amount = 2341818593703234797ull; + input.k_image = crypto::point_t{{0x62, 0xd9, 0xa0, 0xff, 0xb1, 0x89, 0x06, 0xbe, 0xbd, 0xe9, 0xce, 0xd5, 0xc2, 0x04, 0x5b, 0x6b, 0xb4, 0x5f, 0x9c, 0x3b, 0x31, 0xcc, 0x72, 0xc7, 0x55, 0x25, 0x0f, + 0xa2, 0xb2, 0xbf, 0xb1, 0x0c}}.to_key_image(); + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 2613407258u, /* .n_extras = */ 347754399u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 5559118977069213037ull, /* .hsh = */ currency::null_hash, /* cnt = */ 8106306627691316520ull})); + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_htlc input{}; + + input.key_offsets.push_back(9536097715806449708ull); + input.key_offsets.push_back(std::move(currency::ref_by_id{/* .tx_id = */ currency::get_transaction_hash(tx_0), /* .n = */ 9u})); + input.amount = 11357119244607763967ull; + input.k_image = crypto::point_t{{0xcb, 0xec, 0xfb, 0x36, 0x02, 0x1c, 0xe5, 0x64, 0xee, 0x6a, 0xb8, 0x67, 0xb2, 0x8e, 0xe9, 0xef, 0x80, 0x17, 0x34, 0x6f, 0xa8, 0x67, 0x3e, 0x45, 0x3a, 0xe0, 0xd4, + 0x8b, 0x1a, 0x13, 0x75, 0xe2}}.to_key_image(); + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 517318753u, /* .n_extras = */ 1367922888u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 10987762797757012676ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 10767056422067827733ull})); + input.hltc_origin = "htlc-origin"; + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_zc_input input{}; + + input.key_offsets.push_back(16540286509618649069ull); + input.key_offsets.push_back(std::move(currency::ref_by_id{/* .tx_id = */ currency::get_transaction_hash(tx_0), /* .n = */ 4})); + input.k_image = crypto::point_t{{0x53, 0xcf, 0xaf, 0x48, 0x4d, 0xf8, 0xfb, 0x09, 0x4c, 0x01, 0x59, 0x9f, 0xe2, 0x2d, 0x3c, 0x23, 0x96, 0x2d, 0x8c, 0x24, 0x09, 0xf9, 0xd3, 0xe6, 0xf3, 0x27, 0xe8, + 0x7c, 0x7a, 0x90, 0x9c, 0xab}}.to_key_image(); + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 517318753u, /* .n_extras = */ 1367922888u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 10987762797757012676ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 10767056422067827733ull})); + tx.vin.push_back(std::move(input)); + } + + { + currency::txin_multisig input{}; + + input.amount = 14073369620052150183ull; + input.multisig_out_id = crypto::cn_fast_hash("multisig-out-id", 15); + input.sigs_count = 3497547654u; + input.etc_details.push_back(std::move(currency::signed_parts{/* .n_outs = */ 1801772931u, /* .n_extras = */ 167800219u})); + input.etc_details.push_back(std::move(currency::extra_attachment_info{/* .sz = */ 12438971857615319230ull, /* .hsh = */ currency::null_hash, /* .cnt = */ 13515222808659969031ull})); + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c6", t_serializable_object_to_blob(tx)); + } + + /* A wrong reference by an object of the type "ref_by_id": a value of the attribute ".n" representing an offset is greater than a length of a container of outputs.The function "fill_tx_rpc_inputs" + returns false. */ + { + currency::transaction tx{}; + + { + currency::txin_to_key input{}; + + CHECK_AND_ASSERT_GREATER(1968482779, tx_0.vout.size() - 1); + input.key_offsets.push_back(std::move(currency::ref_by_id{currency::get_transaction_hash(tx_0), 1968482779u})); + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c7", t_serializable_object_to_blob(tx)); + } + + // A wrong reference by an object of the type "ref_by_id": hashcode of non-existent transaction is specified. The function "fill_tx_rpc_inputs" returns false. + { + currency::transaction tx{}; + + { + currency::txin_to_key input{}; + + input.key_offsets.push_back(std::move(currency::ref_by_id{currency::null_hash, 0u})); + tx.vin.push_back(std::move(input)); + } + + DO_CALLBACK_PARAMS_STR(events, "c8", t_serializable_object_to_blob(tx)); + } + + return true; +} + +bool fill_tx_rpc_inputs::c1(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.empty(), true); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c2(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 1); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c3(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 1); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c4(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 3); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).amount, UINT64_MAX); + CHECK_AND_ASSERT_EQ(info.ins.at(1).multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.at(1).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(1).kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.empty(), true); + } + + { + CHECK_AND_ASSERT_EQ(info.ins.back().amount, 16730018105294876523ull); + CHECK_AND_ASSERT_EQ(info.ins.back().multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.back().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.back().kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + CHECK_AND_ASSERT_EQ(info.ins.back().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.back().etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c5(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 5); + + for (size_t position{}; position < info.ins.size(); ++position) + { + CHECK_AND_ASSERT_EQ(info.ins.at(position).amount, 0); + CHECK_AND_ASSERT_EQ(info.ins.at(position).multisig_count, 0); + CHECK_AND_ASSERT_EQ(info.ins.at(position).htlc_origin.empty(), true); + + if (position == 0) + { + CHECK_AND_ASSERT_EQ(info.ins.at(position).kimage_or_ms_id.empty(), true); + } + + else + { + CHECK_AND_ASSERT_EQ(info.ins.at(position).kimage_or_ms_id, epee::string_tools::pod_to_hex(currency::null_ki)); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(position).global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(position).etc_options.empty(), true); + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c6(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), true); + CHECK_AND_ASSERT_EQ(info.blob.empty(), true); + CHECK_AND_ASSERT_EQ(info.blob_size, 0); + CHECK_AND_ASSERT_EQ(info.fee, 0); + CHECK_AND_ASSERT_EQ(info.amount, 0); + CHECK_AND_ASSERT_EQ(info.timestamp, 0); + CHECK_AND_ASSERT_EQ(info.keeper_block, 0); + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.pub_key.empty(), true); + CHECK_AND_ASSERT_EQ(info.outs.empty(), true); + + { + CHECK_AND_ASSERT_EQ(info.ins.size(), 5); + + { + CHECK_AND_ASSERT_EQ(info.ins.front().amount, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.front().multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.front().htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().kimage_or_ms_id.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().global_indexes.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.front().etc_options.empty(), true); + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).amount, 2341818593703234797ull); + CHECK_AND_ASSERT_EQ(info.ins.at(1).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(1).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(1).kimage_or_ms_id, "8172e80b8da3bcbce2ee7df42466627bb3559b80bb504f1fd56b460eedbc2ce9"); + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.front(), 5350230927837587142ull); + CHECK_AND_ASSERT_EQ(info.ins.at(1).global_indexes.back(), 0ull); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.front(), "n_outs: 2613407258, n_extras: 347754399"); + CHECK_AND_ASSERT_EQ(info.ins.at(1).etc_options.back(), "cnt: 8106306627691316520, sz: 5559118977069213037, hsh: " + std::string(64, '0')); + } + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(2).amount, 11357119244607763967ull); + CHECK_AND_ASSERT_EQ(info.ins.at(2).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(2).htlc_origin, epee::string_tools::buff_to_hex_nodelimer(std::string{"htlc-origin"})); + CHECK_AND_ASSERT_EQ(info.ins.at(2).kimage_or_ms_id, "f15201980333d6ca8fda90c73814baea0864eb56597e40c38061ec77644585ea"); + CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.front(), 9536097715806449708ull); + CHECK_AND_ASSERT_EQ(info.ins.at(2).global_indexes.back(), 0ull); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.front(), "n_outs: 517318753, n_extras: 1367922888"); + CHECK_AND_ASSERT_EQ(info.ins.at(2).etc_options.back(), "cnt: 10767056422067827733, sz: 10987762797757012676, hsh: " + std::string(64, '0')); + } + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(3).amount, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(3).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(3).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(3).kimage_or_ms_id, "c08b36a7f77185f31a570a7f51aa550122026985e5de7941218510a1e973202e"); + CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.front(), 16540286509618649069ull); + CHECK_AND_ASSERT_EQ(info.ins.at(3).global_indexes.back(), 0ull); + } + + CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.front(), "n_outs: 517318753, n_extras: 1367922888"); + CHECK_AND_ASSERT_EQ(info.ins.at(3).etc_options.back(), "cnt: 10767056422067827733, sz: 10987762797757012676, hsh: " + std::string(64, '0')); + } + } + + { + CHECK_AND_ASSERT_EQ(info.ins.at(4).amount, 14073369620052150183ull); + CHECK_AND_ASSERT_EQ(info.ins.at(4).multisig_count, 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(4).htlc_origin.empty(), true); + CHECK_AND_ASSERT_EQ(info.ins.at(4).kimage_or_ms_id, "aacdff6018af0aae84d7a836a7f0b4309b51a28bfc4f566657c67b903a3ccba5"); + CHECK_AND_ASSERT_EQ(info.ins.at(4).global_indexes.size(), 0ull); + CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.size(), 2ull); + + { + CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.front(), "n_outs: 1801772931, n_extras: 167800219"); + CHECK_AND_ASSERT_EQ(info.ins.at(4).etc_options.back(), "cnt: 13515222808659969031, sz: 12438971857615319230, hsh: " + std::string(64, '0')); + } + } + } + + CHECK_AND_ASSERT_EQ(info.id.empty(), true); + CHECK_AND_ASSERT_EQ(info.extra.empty(), true); + CHECK_AND_ASSERT_EQ(info.attachments.empty(), true); + CHECK_AND_ASSERT_EQ(info.object_in_json.empty(), true); + + return true; +} + +bool fill_tx_rpc_inputs::c7(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.size(), 1); + + { + const auto& input{boost::get(tx.vin.front())}; + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + + { + const auto& reference{boost::get(input.key_offsets.front())}; + + CHECK_AND_ASSERT_EQ(reference.n, 1968482779u); + + { + const auto pointer_entry{core.get_blockchain_storage().get_tx_chain_entry(reference.tx_id)}; + + CHECK_AND_ASSERT(pointer_entry, false); + CHECK_AND_ASSERT(reference.n >= pointer_entry->m_global_output_indexes.size(), false); + } + } + } + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), false); + + return true; +} + +bool fill_tx_rpc_inputs::c8(const currency::core& core, const size_t event_position, const std::vector& events) const +{ + currency::transaction tx{}; + currency::tx_rpc_extended_info info{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(event_position)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.size(), 1); + + { + const auto& input{boost::get(tx.vin.front())}; + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + + { + const auto& reference{boost::get(input.key_offsets.front())}; + + CHECK_AND_ASSERT_EQ(reference.tx_id, currency::null_hash); + CHECK_AND_ASSERT_EQ(reference.n, 0u); + + const auto pointer_entry{core.get_blockchain_storage().get_tx_chain_entry(reference.tx_id)}; + + CHECK_AND_ASSERT(pointer_entry == nullptr, false); + } + } + + CHECK_AND_ASSERT_EQ(core.get_blockchain_storage().fill_tx_rpc_inputs(info, tx), false); + + return true; +} diff --git a/tests/core_tests/daemon_rpc.h b/tests/core_tests/daemon_rpc.h new file mode 100644 index 00000000..72897ddd --- /dev/null +++ b/tests/core_tests/daemon_rpc.h @@ -0,0 +1,22 @@ +// Copyright (c) 2024 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include "chaingen.h" + +struct fill_tx_rpc_inputs : public test_chain_unit_enchanced +{ + fill_tx_rpc_inputs(); + bool generate(std::vector& events) const; + bool c1(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c2(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c3(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c4(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c5(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c6(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c7(const currency::core& core, const size_t event_position, const std::vector& events) const; + bool c8(const currency::core& core, const size_t event_position, const std::vector& events) const; +}; diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl index 0b56af1f..19ec33e9 100644 --- a/tests/core_tests/double_spend.inl +++ b/tests/core_tests/double_spend.inl @@ -95,7 +95,9 @@ bool gen_double_spend_in_tx::generate(std::vector attachments; - if (!construct_tx(bob_account.get_keys(), sources, destinations, attachments, tx_1, this->get_tx_version_from_events(events), uint64_t(0))) + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_from_events(events); + if (!construct_tx(bob_account.get_keys(), sources, destinations, attachments, tx_1, tx_version, tx_hardfork_id, uint64_t(0))) return false; SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_kept_by_block, txs_kept_by_block); diff --git a/tests/core_tests/emission_test.cpp b/tests/core_tests/emission_test.cpp index 035726ca..eb8ccb97 100644 --- a/tests/core_tests/emission_test.cpp +++ b/tests/core_tests/emission_test.cpp @@ -69,7 +69,7 @@ bool emission_test::c1(currency::core& c, size_t ev_index, const std::vector &events) for (size_t i = 0; i < m_pos_entries_to_generate; ++i) destinations.push_back(tx_destination_entry(pos_entry_amount, alice_acc.get_public_address())); - transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(preminer_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0); + transaction tx_1{}; + size_t tx_hardfork_id{}; + r = construct_tx(preminer_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_1); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1); diff --git a/tests/core_tests/escrow_wallet_common.h b/tests/core_tests/escrow_wallet_common.h index f084809c..83cb9585 100644 --- a/tests/core_tests/escrow_wallet_common.h +++ b/tests/core_tests/escrow_wallet_common.h @@ -167,6 +167,7 @@ inline bool build_custom_escrow_template(const std::vector& ev bc_services::contract_private_details& cpd, uint64_t unlock_time, uint64_t expiration_time, size_t nmix, uint64_t b_fee_release, uint64_t custom_config_mask, uint64_t tx_version, + size_t tx_hardfork_id, transaction& escrow_template_tx, /* OUT */ crypto::secret_key& tx_key_sec, /* OUT */ std::vector& used_sources /* IN/OUT */) @@ -231,7 +232,7 @@ inline bool build_custom_escrow_template(const std::vector& ev if (custom_config_mask & eccf_template_additional_attach) attachments.push_back(tx_comment({ get_random_text(1024) })); - r = construct_tx(a_keys, sources, destinations, extra, attachments, escrow_template_tx, tx_version, tx_key_sec, unlock_time, crypt_addr, expiration_time, CURRENCY_TO_KEY_OUT_RELAXED, true, flags); + r = construct_tx(a_keys, sources, destinations, extra, attachments, escrow_template_tx, tx_version, tx_hardfork_id, tx_key_sec, unlock_time, crypt_addr, expiration_time, CURRENCY_TO_KEY_OUT_RELAXED, true, flags); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); if (custom_config_mask & eccf_template_no_tx_flags) @@ -266,6 +267,7 @@ inline bool build_custom_escrow_proposal(const std::vector& ev uint64_t a_fee_proposal, uint64_t b_fee_release, uint64_t custom_config_mask, uint64_t tx_version, + size_t tx_hardfork_id, transaction& escrow_proposal_tx, /* OUT */ std::vector& used_sources,/* IN/OUT */ bc_services::proposal_body* p_pb = nullptr /* OUT */ ) @@ -283,7 +285,7 @@ inline bool build_custom_escrow_proposal(const std::vector& ev p_pb = &local_pb; if (~custom_config_mask & eccf_proposal_sa_empty_body) { - r = build_custom_escrow_template(events, head, a_keys, cpd, template_unlock_time, template_expiration_time, nmix, b_fee_release, custom_config_mask, tx_version, p_pb->tx_template, p_pb->tx_onetime_secret_key, used_sources); + r = build_custom_escrow_template(events, head, a_keys, cpd, template_unlock_time, template_expiration_time, nmix, b_fee_release, custom_config_mask, tx_version, tx_hardfork_id, p_pb->tx_template, p_pb->tx_onetime_secret_key, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_template failed"); } @@ -309,7 +311,7 @@ inline bool build_custom_escrow_proposal(const std::vector& ev account_public_address crypt_addr = cpd.b_addr; crypto::secret_key tx_key_sec; // stub, not used - r = construct_tx(a_keys, sources, destinations, empty_extra, attachments, escrow_proposal_tx, tx_version, tx_key_sec, unlock_time, crypt_addr, expiration_time, 0, true, (~custom_config_mask & eccf_proposal_inv_flags) ? 0 : TX_FLAG_SIGNATURE_MODE_SEPARATE); + r = construct_tx(a_keys, sources, destinations, empty_extra, attachments, escrow_proposal_tx, tx_version, tx_hardfork_id, tx_key_sec, unlock_time, crypt_addr, expiration_time, 0, true, (~custom_config_mask & eccf_proposal_inv_flags) ? 0 : TX_FLAG_SIGNATURE_MODE_SEPARATE); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); append_vector_by_another_vector(used_sources, sources); @@ -321,7 +323,8 @@ inline bool build_custom_escrow_release_template( const account_keys& b_keys, const bc_services::contract_private_details& cpd, uint64_t unlock_time, uint64_t expiration_time, - uint64_t tx_version, + uint64_t tx_version, + size_t tx_hardfork_id, const transaction& escrow_template_tx, /* IN (needed for ms output, tx pub key) */ uint64_t custom_config_mask, /* IN */ transaction& tx /* OUT */ @@ -420,7 +423,7 @@ inline bool build_custom_escrow_release_template( crypto::secret_key one_time_secret_key = AUTO_VAL_INIT(one_time_secret_key); account_public_address crypt_address = AUTO_VAL_INIT(crypt_address); - bool r = construct_tx(b_keys, sources, destinations, extra, attachments, tx, tx_version, one_time_secret_key, unlock_time, crypt_address, expiration_time, 0, true, tx_flags); + bool r = construct_tx(b_keys, sources, destinations, extra, attachments, tx, tx_version, tx_hardfork_id, one_time_secret_key, unlock_time, crypt_address, expiration_time, 0, true, tx_flags); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); bool tx_fully_signed = false; r = sign_multisig_input_in_tx(tx, 0, b_keys, escrow_template_tx, &tx_fully_signed); @@ -470,6 +473,7 @@ inline bool build_custom_escrow_accept_proposal( uint64_t custom_config_mask, /* IN */ crypto::secret_key one_time_secret_key, /* IN */ uint64_t tx_version, /* IN */ + size_t tx_hardfork_id, /* IN */ transaction& tx, /* IN (escrow template), OUT */ std::vector& used_sources /* IN/OUT */ ) @@ -496,9 +500,9 @@ inline bool build_custom_escrow_accept_proposal( // generate release templates bc_services::escrow_relese_templates_body rtb = AUTO_VAL_INIT(rtb); - r = build_custom_escrow_release_template(BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL, b_keys, cpd, release_unlock_time, release_expiration_time, tx_version, tx, custom_config_mask, rtb.tx_normal_template); + r = build_custom_escrow_release_template(BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL, b_keys, cpd, release_unlock_time, release_expiration_time, tx_version, tx_hardfork_id, tx, custom_config_mask, rtb.tx_normal_template); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_release_template(normal) failed"); - r = build_custom_escrow_release_template(BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN, b_keys, cpd, release_unlock_time, release_expiration_time, tx_version, tx, custom_config_mask, rtb.tx_burn_template); + r = build_custom_escrow_release_template(BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN, b_keys, cpd, release_unlock_time, release_expiration_time, tx_version, tx_hardfork_id, tx, custom_config_mask, rtb.tx_burn_template); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_release_template(burn) failed"); // put release templates into the extra @@ -529,7 +533,7 @@ inline bool build_custom_escrow_accept_proposal( sources.back().separately_signed_tx_complete = true; account_public_address crypt_address = AUTO_VAL_INIT(crypt_address); - r = construct_tx(b_keys, sources, destinations, extra, attachments, tx, tx_version, one_time_secret_key, 0, crypt_address, 0, 0, true, tx_flags); // see comment above regarding unlock_time and expiration_time + r = construct_tx(b_keys, sources, destinations, extra, attachments, tx, tx_version, tx_hardfork_id, one_time_secret_key, 0, crypt_address, 0, 0, true, tx_flags); // see comment above regarding unlock_time and expiration_time CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); return true; @@ -545,6 +549,7 @@ inline bool build_custom_escrow_cancel_proposal( uint64_t custom_config_mask, /* IN */ const transaction& escrow_template_tx, /* IN */ uint64_t tx_version, /* IN */ + size_t tx_hardfork_id, /* IN */ transaction& tx, /* OUT */ std::vector& used_sources /* IN/OUT */ ) @@ -568,7 +573,7 @@ inline bool build_custom_escrow_cancel_proposal( // generate cancel release template bc_services::escrow_cancel_templates_body ctb = AUTO_VAL_INIT(ctb); - r = build_custom_escrow_release_template(BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_CANCEL, a_keys, cpd, release_unlock_time, release_expiration_time, tx_version, escrow_template_tx, custom_config_mask, ctb.tx_cancel_template); + r = build_custom_escrow_release_template(BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_CANCEL, a_keys, cpd, release_unlock_time, release_expiration_time, tx_version, tx_hardfork_id, escrow_template_tx, custom_config_mask, ctb.tx_cancel_template); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_release_template(cancel) failed"); // put release templates into the extra @@ -593,7 +598,7 @@ inline bool build_custom_escrow_cancel_proposal( if (~custom_config_mask & eccf_cancellation_inv_crypt_address) crypt_address = cpd.b_addr; crypto::secret_key one_time_secret_key = AUTO_VAL_INIT(one_time_secret_key); - r = construct_tx(a_keys, sources, destinations, extra, attachments, tx, tx_version, one_time_secret_key, unlock_time, crypt_address, expiration_time, 0, true, tx_flags); + r = construct_tx(a_keys, sources, destinations, extra, attachments, tx, tx_version, tx_hardfork_id, one_time_secret_key, unlock_time, crypt_address, expiration_time, 0, true, tx_flags); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); return true; diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index b511aaab..6c805d29 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -503,10 +503,11 @@ bool escrow_incorrect_proposal::generate(std::vector& events) // 1. create normal proposal and make sure it goes correctly through out the whole mechanism (test self-check) // if it fails, it means build_custom_escrow_proposal() produced incorrect proposal - uint64_t tx_version = get_tx_version(get_block_height(blk_1r), m_hardforks); + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_1r), m_hardforks, tx_hardfork_id); uint64_t normal_escrow_mask = eccf_proposal_additional_attach | eccf_template_additional_extra | eccf_template_additional_attach; transaction normal_escrow_proposal_tx = AUTO_VAL_INIT(normal_escrow_proposal_tx); - r = build_custom_escrow_proposal(events, blk_1r, miner_acc.get_keys(), cpd, 0, 0, 0, blk_1r.timestamp + 3600, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, normal_escrow_mask, tx_version, normal_escrow_proposal_tx, used_sources); + r = build_custom_escrow_proposal(events, blk_1r, miner_acc.get_keys(), cpd, 0, 0, 0, blk_1r.timestamp + 3600, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, normal_escrow_mask, tx_version, tx_hardfork_id, normal_escrow_proposal_tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); events.push_back(normal_escrow_proposal_tx); @@ -550,9 +551,9 @@ bool escrow_incorrect_proposal::generate(std::vector& events) uint64_t config_mask = custom_config_masks[i].mask; cpd.comment = "#" + std::to_string(i) + " " + custom_config_masks[i].name; - tx_version = get_tx_version(get_block_height(top_block), m_hardforks); - transaction escrow_proposal_tx = AUTO_VAL_INIT(escrow_proposal_tx); - r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, 0, 0, 0, top_block.timestamp + 3600, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, config_mask, tx_version, escrow_proposal_tx, used_sources); + tx_version = get_tx_version_and_hardfork_id(get_block_height(top_block), m_hardforks, tx_hardfork_id); + transaction escrow_proposal_tx{}; + r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, 0, 0, 0, top_block.timestamp + 3600, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, config_mask, tx_version, tx_hardfork_id, escrow_proposal_tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); LOG_PRINT_YELLOW("proposal tx: " << get_transaction_hash(escrow_proposal_tx) << " is built for mask: " << cpd.comment, LOG_LEVEL_0); @@ -579,10 +580,10 @@ bool escrow_incorrect_proposal::generate(std::vector& events) { cpd.comment = "incorrect unlock time (past)"; - transaction tx = AUTO_VAL_INIT(tx); - tx_version = get_tx_version(get_block_height(top_block), m_hardforks); + transaction tx{}; + tx_version = get_tx_version_and_hardfork_id(get_block_height(top_block), m_hardforks, tx_hardfork_id); // set unlock time to the past (suppose it's incorrect for escrow proposals) - r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, top_block.timestamp, 0, top_block.timestamp, 0, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx, used_sources); + r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, top_block.timestamp, 0, top_block.timestamp, 0, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx_hardfork_id, tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); LOG_PRINT_YELLOW("proposal tx: " << get_transaction_hash(tx) << " is built for " << cpd.comment, LOG_LEVEL_0); events.push_back(tx); @@ -592,11 +593,11 @@ bool escrow_incorrect_proposal::generate(std::vector& events) { cpd.comment = "incorrect unlock time (future)"; - transaction tx = AUTO_VAL_INIT(tx); - tx_version = get_tx_version(get_block_height(top_block), m_hardforks); + transaction tx{}; + tx_version = get_tx_version_and_hardfork_id(get_block_height(top_block), m_hardforks, tx_hardfork_id); // set unlock time to the future (suppose it's incorrect for escrow proposals) uint64_t unlock_time = top_block.timestamp + 365 * 24 * 60 * 60; - r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, unlock_time, 0, unlock_time, 0, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx, used_sources); + r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, unlock_time, 0, unlock_time, 0, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx_hardfork_id, tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); LOG_PRINT_YELLOW("proposal tx: " << get_transaction_hash(tx) << " is built for " << cpd.comment, LOG_LEVEL_0); events.push_back(tx); @@ -606,9 +607,9 @@ bool escrow_incorrect_proposal::generate(std::vector& events) { cpd.comment = "template zero expiration time"; - transaction tx = AUTO_VAL_INIT(tx); - tx_version = get_tx_version(get_block_height(top_block), m_hardforks); - r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, 0, 0, 0, 0, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx, used_sources); + transaction tx{}; + tx_version = get_tx_version_and_hardfork_id(get_block_height(top_block), m_hardforks, tx_hardfork_id); + r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, 0, 0, 0, 0, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx_hardfork_id, tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); LOG_PRINT_YELLOW("proposal tx: " << get_transaction_hash(tx) << " is built for " << cpd.comment, LOG_LEVEL_0); events.push_back(tx); @@ -618,11 +619,11 @@ bool escrow_incorrect_proposal::generate(std::vector& events) { cpd.comment = "proposal non-zero expiration time"; - transaction tx = AUTO_VAL_INIT(tx); - tx_version = get_tx_version(get_block_height(top_block), m_hardforks); + transaction tx{}; + tx_version = get_tx_version_and_hardfork_id(get_block_height(top_block), m_hardforks, tx_hardfork_id); uint64_t proposal_expiration_time = top_block.timestamp + 12 * 60 * 60; uint64_t template_expiration_time = top_block.timestamp + 12 * 60 * 60; - r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, 0, proposal_expiration_time, 0, template_expiration_time, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx, used_sources); + r = build_custom_escrow_proposal(events, top_block, miner_acc.get_keys(), cpd, 0, proposal_expiration_time, 0, template_expiration_time, 0, TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, eccf_normal, tx_version, tx_hardfork_id, tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); LOG_PRINT_YELLOW("proposal tx: " << get_transaction_hash(tx) << " is built for " << cpd.comment, LOG_LEVEL_0); events.push_back(tx); @@ -1149,17 +1150,18 @@ bool escrow_incorrect_proposal_acceptance::generate(std::vector& events) const destinations.push_back(tx_destination_entry(chunk_amount, bob_acc.get_public_address())); } // no change back to the miner - it will become a fee - transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0); + transaction tx_1{}; + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_1); @@ -1949,7 +1952,8 @@ bool escrow_incorrect_cancel_proposal::generate(std::vector& e } // no change back to the miner - it will become a fee transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0); + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_1); @@ -1969,27 +1973,27 @@ bool escrow_incorrect_cancel_proposal::generate(std::vector& e // create normal escrow proposal bc_services::proposal_body prop = AUTO_VAL_INIT(prop); - uint64_t tx_version = get_tx_version(get_block_height(blk_1r), m_hardforks); + uint64_t tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_1r), m_hardforks, tx_hardfork_id); transaction escrow_proposal_tx = AUTO_VAL_INIT(escrow_proposal_tx); - r = build_custom_escrow_proposal(events, blk_1r, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_1r.timestamp + 36000, 0, TESTS_DEFAULT_FEE, m_bob_fee_release, eccf_normal, tx_version, escrow_proposal_tx, used_sources, &prop); + r = build_custom_escrow_proposal(events, blk_1r, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_1r.timestamp + 36000, 0, TESTS_DEFAULT_FEE, m_bob_fee_release, eccf_normal, tx_version, tx_hardfork_id, escrow_proposal_tx, used_sources, &prop); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed"); events.push_back(escrow_proposal_tx); MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, escrow_proposal_tx); // create normal escrow proposal acceptance transaction escrow_normal_acceptance_tx = prop.tx_template; - tx_version = get_tx_version(get_block_height(blk_2), m_hardforks); + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_2), m_hardforks, tx_hardfork_id); uint64_t normal_acceptance_mask = eccf_acceptance_no_tsa_compression; - r = build_custom_escrow_accept_proposal(events, blk_2, 0, bob_acc.get_keys(), m_cpd, 0, 0, 0, 0, TESTS_DEFAULT_FEE, m_bob_fee_release, normal_acceptance_mask, prop.tx_onetime_secret_key, tx_version, escrow_normal_acceptance_tx, used_sources); + r = build_custom_escrow_accept_proposal(events, blk_2, 0, bob_acc.get_keys(), m_cpd, 0, 0, 0, 0, TESTS_DEFAULT_FEE, m_bob_fee_release, normal_acceptance_mask, prop.tx_onetime_secret_key, tx_version, tx_hardfork_id, escrow_normal_acceptance_tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_accept_proposal failed"); events.push_back(escrow_normal_acceptance_tx); MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, escrow_normal_acceptance_tx); // create normal cancel proposal - tx_version = get_tx_version(get_block_height(blk_3), m_hardforks); + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_3), m_hardforks, tx_hardfork_id); transaction escrow_normal_cancel_proposal_tx = AUTO_VAL_INIT(escrow_normal_cancel_proposal_tx); - r = build_custom_escrow_cancel_proposal(events, blk_3, 0, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_3.timestamp + 3600, TESTS_DEFAULT_FEE, eccf_normal, prop.tx_template, tx_version, escrow_normal_cancel_proposal_tx, used_sources); + r = build_custom_escrow_cancel_proposal(events, blk_3, 0, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_3.timestamp + 3600, TESTS_DEFAULT_FEE, eccf_normal, prop.tx_template, tx_version, tx_hardfork_id, escrow_normal_cancel_proposal_tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_cancel_proposal failed"); events.push_back(escrow_normal_cancel_proposal_tx); @@ -2057,9 +2061,9 @@ bool escrow_incorrect_cancel_proposal::generate(std::vector& e uint64_t mask = ccm_el.mask; transaction incorrect_cancellation_proposal_tx = prop.tx_template; - uint64_t tx_version = get_tx_version(get_block_height(blk_3), m_hardforks); + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_3), m_hardforks, tx_hardfork_id); r = build_custom_escrow_cancel_proposal(events, prev_block, 0, alice_acc.get_keys(), m_cpd, ccm_el.unlock_time, ccm_el.expiration_time, ccm_el.release_unlock_time, ccm_el.release_expiration_time, - TESTS_DEFAULT_FEE, mask, prop.tx_template, tx_version, incorrect_cancellation_proposal_tx, used_sources); + TESTS_DEFAULT_FEE, mask, prop.tx_template, tx_version, tx_hardfork_id, incorrect_cancellation_proposal_tx, used_sources); CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_cancel_proposal failed"); // In order to use the same escrow proposal to test different invalid cancellations we need to switch chains after each try @@ -2985,9 +2989,10 @@ bool escrow_proposal_acceptance_in_alt_chain::generate(std::vector& events r = fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), m_amount * m_fake_amounts_count + TESTS_DEFAULT_FEE, 0); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); - transaction tx_0 = AUTO_VAL_INIT(tx_0); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + transaction tx_0{}; + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); uint64_t burned_tx_amount_total = get_burned_amount(tx_0); diff --git a/tests/core_tests/hard_fork_1.cpp b/tests/core_tests/hard_fork_1.cpp index 861b29aa..a4829231 100644 --- a/tests/core_tests/hard_fork_1.cpp +++ b/tests/core_tests/hard_fork_1.cpp @@ -239,7 +239,7 @@ bool hard_fork_1_unlock_time_2_in_coinbase::generate(std::vector& CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); transaction tx_1 = AUTO_VAL_INIT(tx_1); r = construct_tx(alice_acc.get_keys(), sources, std::vector{ tx_destination_entry(MK_TEST_COINS(90) - TESTS_DEFAULT_FEE, miner_acc.get_public_address()) }, - empty_attachment, tx_1, get_tx_version_from_events(events), stake_lock_time /* try to use stake unlock time -- should not work as it is not a coinbase */); + empty_attachment, tx_1, get_tx_version_from_events(events), 0, stake_lock_time /* try to use stake unlock time -- should not work as it is not a coinbase */); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); DO_CALLBACK(events, "mark_invalid_tx"); @@ -882,7 +882,7 @@ bool hard_fork_1_pos_locked_height_vs_time::generate(std::vector{ tx_destination_entry(stake_amount / 2, miner_acc.get_public_address()) }, - empty_attachment, tx_1, get_tx_version_from_events(events), stake_unlock_time /* try to use stake unlock time -- should not work as it is not a coinbase */); + empty_attachment, tx_1, get_tx_version_from_events(events), 0, stake_unlock_time /* try to use stake unlock time -- should not work as it is not a coinbase */); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); DO_CALLBACK(events, "mark_invalid_tx"); diff --git a/tests/core_tests/hard_fork_4.cpp b/tests/core_tests/hard_fork_4.cpp index a87a1479..dc5fc492 100644 --- a/tests/core_tests/hard_fork_4.cpp +++ b/tests/core_tests/hard_fork_4.cpp @@ -82,7 +82,9 @@ bool hard_fork_4_consolidated_txs::generate(std::vector& event 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, + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, tx_version, tx_hardfork_id, 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"); @@ -119,7 +121,9 @@ bool hard_fork_4_consolidated_txs::generate(std::vector& event std::vector destinations; - r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, get_tx_version_from_events(events), one_time_secret_key, + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id); + r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, tx_version, tx_hardfork_id, one_time_secret_key, 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"); diff --git a/tests/core_tests/hard_fork_5.cpp b/tests/core_tests/hard_fork_5.cpp new file mode 100644 index 00000000..bd0cd4df --- /dev/null +++ b/tests/core_tests/hard_fork_5.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2024 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "chaingen.h" +#include "hard_fork_5.h" +#include "random_helper.h" + +using namespace currency; + +hard_fork_5_tx_version::hard_fork_5_tx_version() +{ + REGISTER_CALLBACK_METHOD(hard_fork_5_tx_version, c1); +} + +bool hard_fork_5_tx_version::generate(std::vector& events) const +{ + // + // Test idea: ensure that the correct tx.hardfork_id is required after HF5. + // + bool r = false; + uint64_t ts = test_core_time::get_time(); + m_accounts.resize(TOTAL_ACCS_COUNT); + 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, miner_acc, ts); + DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks + REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); + + // make a simple tx just to check HF5 tx.hardfork_id rule basic validity + MAKE_TX(events, tx_1, miner_acc, alice_acc, MK_TEST_COINS(1), blk_0r); + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1); + + // + // construct a tx with an incorrect hardfork_id and make sure it won't be accepted by either the tx pool or the core + // + std::vector sources; + std::vector destinations; + + r = fill_tx_sources_and_destinations(events, blk_1, miner_acc, alice_acc, MK_TEST_COINS(7), TX_DEFAULT_FEE, 4, sources, destinations); + CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); + + transaction tx_2{}; + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_1) + 1, m_hardforks, tx_hardfork_id); + size_t incorrect_tx_hardfork_id = 0; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_2, tx_version, incorrect_tx_hardfork_id, 0); // note using incorrect hardfork id here + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + // mark as invalid, shouldn't be accepted by the tx pool + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_2); + + // now add tx_2 as 'kept_by_block', with tx pool checks turned off + ADD_CUSTOM_EVENT(events, event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, true)); + events.push_back(tx_2); // now tx should be accepted by the pool + ADD_CUSTOM_EVENT(events, event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false)); + // the block shouldn't be accepted, because of invalid tx_2 + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_2_bad, blk_1, miner_acc, tx_2); + + + // + // reconstruct the same tx, now using the correct tx_hardfork_id, and make sure it will be accepted + // + tx_2 = transaction{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_2, tx_version, tx_hardfork_id, 0); + CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); + ADD_CUSTOM_EVENT(events, tx_2); + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1, miner_acc, tx_2); + + REWIND_BLOCKS_N_WITH_TIME(events, blk_2r, blk_2, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + // epilogue + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool hard_fork_5_tx_version::c1(currency::core& c, size_t ev_index, const std::vector &events) +{ + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); + + size_t blocks_fetched = 0; + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5); + + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", MK_TEST_COINS(8)), false, ""); + + return true; +} diff --git a/tests/core_tests/hard_fork_5.h b/tests/core_tests/hard_fork_5.h new file mode 100644 index 00000000..61c79c48 --- /dev/null +++ b/tests/core_tests/hard_fork_5.h @@ -0,0 +1,14 @@ +// Copyright (c) 2024 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once +#include "chaingen.h" +#include "wallet_tests_basic.h" + + +struct hard_fork_5_tx_version : public wallet_test +{ + hard_fork_5_tx_version(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector &events); +}; diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp index e73c6cef..33361093 100644 --- a/tests/core_tests/integer_overflow.cpp +++ b/tests/core_tests/integer_overflow.cpp @@ -157,9 +157,10 @@ bool gen_uint_overflow_2::generate(std::vector& events) const // sources.front().amount = destinations[0].amount + destinations[2].amount + destinations[3].amount + TESTS_DEFAULT_FEE destinations.push_back(tx_destination_entry(sources.front().amount - TX_MAX_TRANSFER_AMOUNT - TX_MAX_TRANSFER_AMOUNT + 1 - TESTS_DEFAULT_FEE, bob_addr)); - currency::transaction tx_1; + currency::transaction tx_1{}; std::vector attachments; - if (!construct_tx(miner_account.get_keys(), sources, destinations, attachments, tx_1, get_tx_version_from_events(events), 0)) + size_t tx_hardfork_id{}; + if (!construct_tx(miner_account.get_keys(), sources, destinations, attachments, tx_1, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0)) return false; events.push_back(tx_1); @@ -186,7 +187,7 @@ bool gen_uint_overflow_2::generate(std::vector& events) const currency::transaction tx_2; std::vector attachments2; - if (!construct_tx(bob_account.get_keys(), sources, destinations, attachments2, tx_2, get_tx_version_from_events(events), 0)) + if (!construct_tx(bob_account.get_keys(), sources, destinations, attachments2, tx_2, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0)) return false; events.push_back(tx_2); diff --git a/tests/core_tests/misc_tests.cpp b/tests/core_tests/misc_tests.cpp index b9ccab13..c7b738ed 100644 --- a/tests/core_tests/misc_tests.cpp +++ b/tests/core_tests/misc_tests.cpp @@ -237,8 +237,9 @@ bool block_template_vs_invalid_txs_from_pool::generate(std::vector sources; r = fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), de.amount + TESTS_DEFAULT_FEE, 0); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); - transaction tx_1m = AUTO_VAL_INIT(tx_1m); - r = construct_tx(miner_acc.get_keys(), sources, std::vector({ de }), empty_attachment, tx_1m, get_tx_version_from_events(events), 0); + transaction tx_1m; + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, std::vector({ de }), empty_attachment, tx_1m, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_1m); @@ -269,18 +270,18 @@ bool block_template_vs_invalid_txs_from_pool::generate(std::vector(boost::get(tx_1m.vout[se.real_output_in_tx_index]).target).keys.size(); se.ms_sigs_count = 1; - transaction tx_2m = AUTO_VAL_INIT(tx_2m); + transaction tx_2m{}; r = construct_tx(bob_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, miner_acc.get_public_address()) }), - empty_attachment, tx_2m, get_tx_version_from_events(events), 0); + empty_attachment, tx_2m, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); bool input_fully_signed = false; r = sign_multisig_input_in_tx(tx_2m, 0, bob_acc.get_keys(), tx_1m, &input_fully_signed); CHECK_AND_ASSERT_MES(r && input_fully_signed, false, "sign_multisig_input_in_tx failed, input_fully_signed=" << input_fully_signed); events.push_back(tx_2m); - transaction tx_2ma = AUTO_VAL_INIT(tx_2ma); + transaction tx_2ma{}; r = construct_tx(bob_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, miner_acc.get_public_address()) }), - empty_attachment, tx_2ma, get_tx_version_from_events(events), 0); + empty_attachment, tx_2ma, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); input_fully_signed = false; r = sign_multisig_input_in_tx(tx_2ma, 0, bob_acc.get_keys(), tx_1m, &input_fully_signed); @@ -436,8 +437,9 @@ bool test_blockchain_vs_spent_multisig_outs::generate(std::vector destinations; r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc, alice_acc, m_alice_initial_balance, TESTS_DEFAULT_FEE, 0, sources, destinations, true /* spends */, false /* unlock time */); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); ADD_CUSTOM_EVENT(events, tx_0); @@ -701,7 +702,8 @@ bool asset_depoyment_and_few_zc_utxos::generate(std::vector& e m_alice_initial_balance = TESTS_DEFAULT_FEE * 100; r = fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), m_alice_initial_balance + TESTS_DEFAULT_FEE, 0); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); ADD_CUSTOM_EVENT(events, tx_0); @@ -1017,16 +1019,10 @@ bool asset_operation_and_hardfork_checks::generate( CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); - tx_version = get_tx_version(get_block_height(blk_0r), - m_hardforks); + size_t tx_hardfork_id{}; + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_0r), m_hardforks, tx_hardfork_id); - success = construct_tx(miner.get_keys(), - sources, - destinations, - empty_attachment, - tx_0, - tx_version, - 0); + success = construct_tx(miner.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version, tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_0"); @@ -1058,7 +1054,7 @@ bool asset_operation_and_hardfork_checks::generate( /* to = */ alice.get_public_address(), /* asset_id = */ currency::null_pkey); - tx_version = get_tx_version(get_block_height(blk_1r), m_hardforks); + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_1r), m_hardforks, tx_hardfork_id); size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_1r)); fill_ado_version_based_onhardfork(m_ado_hello, hf_n); fill_adb_version_based_onhardfork(*m_ado_hello.opt_descriptor, hf_n); @@ -1069,6 +1065,7 @@ bool asset_operation_and_hardfork_checks::generate( empty_attachment, tx_1, tx_version, + tx_hardfork_id, stub, 0); @@ -1105,8 +1102,7 @@ bool asset_operation_and_hardfork_checks::generate( CHECK_AND_ASSERT_MES(success, false, "fail to fill sources, destinations"); - tx_version = get_tx_version(get_block_height(blk_2r), - m_hardforks); + tx_version = get_tx_version_and_hardfork_id(get_block_height(blk_2r), m_hardforks, tx_hardfork_id); hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); fill_ado_version_based_onhardfork(m_ado_hello, hf_n); @@ -1118,6 +1114,7 @@ bool asset_operation_and_hardfork_checks::generate( empty_attachment, tx_2, tx_version, + tx_hardfork_id, stub, 0); @@ -1159,6 +1156,7 @@ bool asset_operation_and_hardfork_checks::generate( /* attachments = */ {m_ado_bye}, tx_3, tx_version, + hf_n, 0); CHECK_AND_ASSERT_MES(success, false, "fail to construct tx_3"); @@ -1199,6 +1197,7 @@ bool asset_operation_and_hardfork_checks::generate( /* attachments = */ {m_ado_bye}, tx_4, tx_version, + hf_n, stub, 0); @@ -1270,18 +1269,6 @@ bool asset_operation_and_hardfork_checks::c2( asset_operation_in_consolidated_tx::asset_operation_in_consolidated_tx() { - m_adb_alice_currency.version = ASSET_DESCRIPTOR_BASE_HF4_VER; - m_adb_alice_currency.total_max_supply = 1'000'000'000'000'000'000; - m_adb_alice_currency.current_supply = 1'000'000'000'000'000'000; - m_adb_alice_currency.ticker = "ALC"; - m_adb_alice_currency.full_name = "ALICE"; - m_adb_alice_currency.meta_info = "Currency created by Alice"; - m_adb_alice_currency.hidden_supply = false; - - m_ado_alice_currency.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; - m_ado_alice_currency.opt_asset_id = currency::null_pkey; - m_ado_alice_currency.version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; - REGISTER_CALLBACK_METHOD(asset_operation_in_consolidated_tx, assert_balances); REGISTER_CALLBACK_METHOD(asset_operation_in_consolidated_tx, assert_alice_currency_not_registered); } @@ -1289,11 +1276,13 @@ asset_operation_in_consolidated_tx::asset_operation_in_consolidated_tx() bool asset_operation_in_consolidated_tx::generate(std::vector& events) const { // Test idea: make sure that the core rule prohibiting operations with assets in TX_FLAG_SIGNATURE_MODE_SEPARATE transactions works. - bool success {}; - transaction tx_2 {}; - uint64_t tx_version {}; - crypto::secret_key one_time {}; - tx_generation_context context_tx_2 {}; + bool success{}; + transaction tx_2{}; + uint64_t tx_version{}; + crypto::secret_key one_time{}; + tx_generation_context context_tx_2{}; + asset_descriptor_base adb_alice_currency{}; + asset_descriptor_operation ado_alice_currency{}; GENERATE_ACCOUNT(miner); GENERATE_ACCOUNT(alice); GENERATE_ACCOUNT(bob); @@ -1301,8 +1290,19 @@ bool asset_operation_in_consolidated_tx::generate(std::vector& m_accounts.push_back(miner); m_accounts.push_back(alice); m_accounts.push_back(bob); - m_adb_alice_currency.owner = m_accounts.at(ALICE_ACC_IDX).get_public_address().spend_public_key; - m_ado_alice_currency.opt_descriptor = m_adb_alice_currency; + + adb_alice_currency.version = ASSET_DESCRIPTOR_BASE_HF4_VER; + adb_alice_currency.total_max_supply = 1'000'000'000'000'000'000; + adb_alice_currency.current_supply = 1'000'000'000'000'000'000; + adb_alice_currency.ticker = "ALC"; + adb_alice_currency.full_name = "ALICE"; + adb_alice_currency.meta_info = "Currency created by Alice"; + adb_alice_currency.hidden_supply = false; + adb_alice_currency.owner = m_accounts.at(ALICE_ACC_IDX).get_public_address().spend_public_key; + ado_alice_currency.opt_descriptor = adb_alice_currency; + ado_alice_currency.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; + ado_alice_currency.opt_asset_id = currency::null_pkey; + ado_alice_currency.version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); DO_CALLBACK(events, "configure_core"); @@ -1317,16 +1317,16 @@ bool asset_operation_in_consolidated_tx::generate(std::vector& DO_CALLBACK(events, "assert_balances"); { - std::vector sources {}; - std::vector destinations {}; + std::vector sources{}; + std::vector destinations{}; success = fill_tx_sources(sources, events, blk_2r, alice.get_keys(), MK_TEST_COINS(5), 1); CHECK_AND_ASSERT_MES(success, false, "failed to fill transaction sources on step 1"); destinations.emplace_back(MK_TEST_COINS(5), bob.get_public_address()); destinations.emplace_back(MK_TEST_COINS(/* 10 - 5 - 1 = */ 4), alice.get_public_address()); tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); - success = construct_tx(alice.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_2, tx_version, one_time, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, TESTS_DEFAULT_FEE, - context_tx_2); + success = construct_tx(alice.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_2, tx_version, one_time, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, TESTS_DEFAULT_FEE, + context_tx_2); CHECK_AND_ASSERT_MES(success, false, "failed to construct transaction tx_2 on step 1"); } @@ -1335,26 +1335,26 @@ bool asset_operation_in_consolidated_tx::generate(std::vector& ADD_CUSTOM_EVENT(events, tx_2); { - std::vector sources {}; - std::vector destinations {}; + std::vector sources{}; + std::vector destinations{}; success = fill_tx_sources(sources, events, blk_2r, bob.get_keys(), MK_TEST_COINS(5), 0); CHECK_AND_ASSERT_MES(success, false, "failed to fill transaction sources on step 2"); - for(tx_source_entry& source : sources) + + for (tx_source_entry& source : sources) { source.separately_signed_tx_complete = true; } + destinations.emplace_back(MK_TEST_COINS(5), alice.get_public_address()); destinations.emplace_back(MK_TEST_COINS(/* 10 - 5 - 0 = */ 5), bob.get_public_address()); - destinations.emplace_back(m_adb_alice_currency.current_supply, alice.get_public_address(), null_pkey); + destinations.emplace_back(adb_alice_currency.current_supply, alice.get_public_address(), null_pkey); tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); - fill_ado_version_based_onhardfork(m_ado_alice_currency, hf_n); - fill_adb_version_based_onhardfork(*m_ado_alice_currency.opt_descriptor, hf_n); - - - success = construct_tx(bob.get_keys(), sources, destinations, { m_ado_alice_currency }, empty_attachment, tx_2, tx_version, one_time, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, - /* fee = */ 0, context_tx_2); + fill_ado_version_based_onhardfork(ado_alice_currency, hf_n); + fill_adb_version_based_onhardfork(*ado_alice_currency.opt_descriptor, hf_n); + success = construct_tx(bob.get_keys(), sources, destinations, {ado_alice_currency}, empty_attachment, tx_2, tx_version, one_time, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, + /* fee = */ 0, context_tx_2); CHECK_AND_ASSERT_MES(success, false, "failed to construct transaction tx_2 on step 2"); } @@ -1363,15 +1363,15 @@ bool asset_operation_in_consolidated_tx::generate(std::vector& // Core rejects transaction tx_2. The balances of Alice, Bob haven't changed: Alice has 10 coins, Bob has 10 coins. DO_CALLBACK(events, "assert_balances"); // Alice's asset hasn't registered, because transaction tx_2 was rejected. - DO_CALLBACK(events, "assert_alice_currency_not_registered"); + DO_CALLBACK_PARAMS_STR(events, "assert_alice_currency_not_registered", t_serializable_object_to_blob(ado_alice_currency)); return true; } -bool asset_operation_in_consolidated_tx::assert_balances(currency::core& c, size_t ev_index, const std::vector& events) +bool asset_operation_in_consolidated_tx::assert_balances(currency::core& c, size_t ev_index, const std::vector& events) const { - std::shared_ptr alice_wallet{init_playtime_test_wallet(events, c, ALICE_ACC_IDX)}; - std::shared_ptr bob_wallet{init_playtime_test_wallet(events, c, BOB_ACC_IDX)}; + const auto alice_wallet{init_playtime_test_wallet_t(events, c, ALICE_ACC_IDX)}; + const auto bob_wallet{init_playtime_test_wallet_t(events, c, BOB_ACC_IDX)}; alice_wallet->refresh(); bob_wallet->refresh(); @@ -1382,14 +1382,28 @@ bool asset_operation_in_consolidated_tx::assert_balances(currency::core& c, size return true; } -bool asset_operation_in_consolidated_tx::assert_alice_currency_not_registered(currency::core& c, size_t ev_index, const std::vector& events) +bool asset_operation_in_consolidated_tx::assert_alice_currency_not_registered(const currency::core& c, size_t ev_index, const std::vector& events) const { - crypto::point_t asset_id_point{}; crypto::public_key asset_id{}; - currency::asset_descriptor_base stub{}; + asset_descriptor_operation ado{}; - CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(m_ado_alice_currency, &asset_id_point, &asset_id), false, "fail to calculate asset id"); - CHECK_AND_ASSERT_MES(!c.get_blockchain_storage().get_asset_info(asset_id, stub), false, "unregistered asset has info"); + { + const auto serialized_ado{boost::get(events.at(ev_index)).callback_params}; + + CHECK_AND_ASSERT_MES(t_unserializable_object_from_blob(ado, serialized_ado), false, "ADO deserialization failed"); + } + + { + crypto::point_t point_asset_id{}; + + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &point_asset_id, &asset_id), false, "fail to calculate asset id"); + } + + { + currency::asset_descriptor_base adb_stub{}; + + CHECK_AND_ASSERT_MES(!c.get_blockchain_storage().get_asset_info(asset_id, adb_stub), false, "unregistered asset has info"); + } return true; } @@ -2068,6 +2082,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec GENERATE_ACCOUNT(miner); GENERATE_ACCOUNT(alice); transaction tx_0{}, tx_1{}, tx_2{}, tx_3{}, tx_4{}; + size_t tx_hardfork_id{}; m_accounts.push_back(miner); m_accounts.push_back(alice); @@ -2091,7 +2106,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec success = fill_tx_sources_and_destinations(events, top, miner.get_keys(), alice.get_public_address(), MK_TEST_COINS(8), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_EQ(success, true); - success = construct_tx(miner.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version(get_block_height(top), m_hardforks), 0); + success = construct_tx(miner.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_and_hardfork_id(get_block_height(top), m_hardforks, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_EQ(success, true); } @@ -2115,7 +2130,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec destinations.emplace_back(ado.opt_descriptor->current_supply, alice.get_public_address(), null_pkey); CHECK_AND_ASSERT_EQ(ado.opt_descriptor->total_max_supply, 0); CHECK_AND_ASSERT_EQ(ado.opt_descriptor->total_max_supply, ado.opt_descriptor->current_supply); - success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_1, get_tx_version(get_block_height(top), m_hardforks), one_time, 0); + success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_1, get_tx_version_and_hardfork_id(get_block_height(top), m_hardforks, tx_hardfork_id), tx_hardfork_id, one_time, 0); CHECK_AND_ASSERT_EQ(success, true); } @@ -2140,7 +2155,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec CHECK_AND_ASSERT_EQ(success, true); destinations.emplace_back(ado.opt_descriptor->current_supply, alice.get_public_address(), null_pkey); CHECK_AND_ASSERT_MES(ado.opt_descriptor->current_supply > ado.opt_descriptor->total_max_supply, false, "current_supply <= total_max_supply"); - success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_2, get_tx_version(get_block_height(top), m_hardforks), one_time, 0); + success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_2, get_tx_version_and_hardfork_id(get_block_height(top), m_hardforks, tx_hardfork_id), tx_hardfork_id, one_time, 0); CHECK_AND_ASSERT_EQ(success, true); } @@ -2165,7 +2180,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec CHECK_AND_ASSERT_EQ(success, true); destinations.emplace_back(ado.opt_descriptor->current_supply, alice.get_public_address(), null_pkey); CHECK_AND_ASSERT(ado.opt_descriptor->current_supply <= ado.opt_descriptor->total_max_supply, false); - success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_3, get_tx_version(get_block_height(top), m_hardforks), one_time, 0); + success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_3, get_tx_version_and_hardfork_id(get_block_height(top), m_hardforks, tx_hardfork_id), tx_hardfork_id, one_time, 0); CHECK_AND_ASSERT_EQ(success, true); } diff --git a/tests/core_tests/multiassets_test.h b/tests/core_tests/multiassets_test.h index d306a0f4..5b367533 100644 --- a/tests/core_tests/multiassets_test.h +++ b/tests/core_tests/multiassets_test.h @@ -74,12 +74,8 @@ struct asset_operation_in_consolidated_tx : public wallet_test public: asset_operation_in_consolidated_tx(); bool generate(std::vector& events) const; - bool assert_balances(currency::core& c, size_t ev_index, const std::vector& events); - bool assert_alice_currency_not_registered(currency::core& c, size_t ev_index, const std::vector& events); - -private: - mutable currency::asset_descriptor_base m_adb_alice_currency{}; - mutable currency::asset_descriptor_operation m_ado_alice_currency{}; + bool assert_balances(currency::core& c, size_t ev_index, const std::vector& events) const; + bool assert_alice_currency_not_registered(const currency::core& c, size_t ev_index, const std::vector& events) const; }; struct eth_signed_asset_basics : public wallet_test diff --git a/tests/core_tests/multisig_wallet_tests.cpp b/tests/core_tests/multisig_wallet_tests.cpp index ef4f0c34..4c2dc2dc 100644 --- a/tests/core_tests/multisig_wallet_tests.cpp +++ b/tests/core_tests/multisig_wallet_tests.cpp @@ -880,7 +880,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), ms_addr_list, amount, TESTS_DEFAULT_FEE, 0, sources, destinations, true, true, 4); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx = AUTO_VAL_INIT(tx); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r == false, false, "construct_tx was expected to fail, but successed"); @@ -893,7 +893,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_1); @@ -917,7 +917,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons // Transaction should be successfully created, but rejected by the core transaction tx_2 = AUTO_VAL_INIT(tx_2); - r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ de }), empty_attachment, tx_2, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ de }), empty_attachment, tx_2, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); bool tx_fully_signed = false; r = sign_multisig_input_in_tx(tx_2, 0, bob_acc.get_keys(), tx_1, &tx_fully_signed); @@ -947,7 +947,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons se.ms_sigs_count = 2; transaction tx_3 = AUTO_VAL_INIT(tx_3); - r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, bob_acc.get_public_address()) }), empty_attachment, tx_3, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, bob_acc.get_public_address()) }), empty_attachment, tx_3, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); r = sign_multisig_input_in_tx(tx_3, 0, bob_acc.get_keys(), tx_1, &tx_fully_signed); CHECK_AND_ASSERT_MES(r && !tx_fully_signed, false, "sign_multisig_input_in_tx failed, tx_fully_signed : " << tx_fully_signed); @@ -966,7 +966,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_4 = AUTO_VAL_INIT(tx_4); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_4, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_4, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_4); @@ -984,7 +984,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons se.ms_sigs_count = 3; transaction tx_5 = AUTO_VAL_INIT(tx_5); - r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, alice_acc.get_public_address()) }), empty_attachment, tx_5, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, alice_acc.get_public_address()) }), empty_attachment, tx_5, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); // use sign_multisig_input_in_tx_custom to create tx with more signatures (3) than minimum_sigs (1) @@ -1009,7 +1009,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_6 = AUTO_VAL_INIT(tx_6); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_6, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_6, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_6); @@ -1028,7 +1028,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons se.ms_sigs_count = 4; transaction tx_7 = AUTO_VAL_INIT(tx_7); - r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, alice_acc.get_public_address()) }), empty_attachment, tx_7, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, alice_acc.get_public_address()) }), empty_attachment, tx_7, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); // use sign_multisig_input_in_tx_custom to create tx with more signatures (4) than minimum_sigs (1) @@ -1051,7 +1051,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_8 = AUTO_VAL_INIT(tx_8); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_8, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_8, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_8); @@ -1071,7 +1071,7 @@ bool multisig_minimum_sigs::generate(std::vector& events) cons se.ms_sigs_count = redundant_keys_count; transaction tx_9 = AUTO_VAL_INIT(tx_9); - r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, alice_acc.get_public_address()) }), empty_attachment, tx_9, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, alice_acc.get_public_address()) }), empty_attachment, tx_9, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); boost::get(tx_9.signatures[0]).s.resize(redundant_keys_count, invalid_signature); @@ -1202,7 +1202,7 @@ bool multisig_and_unlock_time::generate(std::vector& events) c uint64_t unlock_time_2 = blk_0r.timestamp + DIFFICULTY_TOTAL_TARGET * 6 + CURRENCY_LOCKED_TX_ALLOWED_DELTA_SECONDS; transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), unlock_time, CURRENCY_TO_KEY_OUT_RELAXED, true); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0, unlock_time, CURRENCY_TO_KEY_OUT_RELAXED, true); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); CHECK_AND_ASSERT_MES(get_tx_max_unlock_time(tx_1) == unlock_time, false, "Unlock time was not correctly set"); events.push_back(tx_1); @@ -1232,7 +1232,7 @@ bool multisig_and_unlock_time::generate(std::vector& events) c // tx_2 should be created ok, but rejected by the core, as one of input refers to a locked tx // Note: tx_2 has unlock_time_2 specified transaction tx_2 = AUTO_VAL_INIT(tx_2); - r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_2, get_tx_version_from_events(events), unlock_time_2, CURRENCY_TO_KEY_OUT_RELAXED, true); + r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_2, get_tx_version_from_events(events), 0, unlock_time_2, CURRENCY_TO_KEY_OUT_RELAXED, true); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); bool tx_fully_signed = false; @@ -1256,7 +1256,7 @@ bool multisig_and_unlock_time::generate(std::vector& events) c r = fill_tx_sources_and_destinations(events, blk_2, alice_acc, bob_acc, amount - TESTS_DEFAULT_FEE * 2, TESTS_DEFAULT_FEE, 0 /*nmix*/, sources, destinations, true, false /* check_for_unlocktime */); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_3{}; - r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_3, get_tx_version_from_events(events), 0); + r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_3, get_tx_version_from_events(events), 0, 0 /* unlock time */, 0 /* mix attib */); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); ADD_CUSTOM_EVENT(events, tx_3); @@ -1281,7 +1281,7 @@ bool multisig_and_unlock_time::generate(std::vector& events) c crypto::secret_key stub_key = AUTO_VAL_INIT(stub_key); etc_tx_details_expiration_time extra_expiration_time = AUTO_VAL_INIT(extra_expiration_time); extra_expiration_time.v = expiration_time; - r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ extra_expiration_time }), empty_attachment, tx_4, get_tx_version_from_events(events), stub_key, 0, CURRENCY_TO_KEY_OUT_RELAXED, true); + r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ extra_expiration_time }), empty_attachment, tx_4, get_tx_version_from_events(events), 0, stub_key, 0, CURRENCY_TO_KEY_OUT_RELAXED, true); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); CHECK_AND_ASSERT_MES(get_tx_expiration_time(tx_4) == expiration_time, false, "Expiration time was not correctly set"); DO_CALLBACK(events, "mark_invalid_tx"); @@ -1289,7 +1289,7 @@ bool multisig_and_unlock_time::generate(std::vector& events) c // add similar tx (same sources and destinations) with no expiration_time - should be accepted by the core transaction tx_5 = AUTO_VAL_INIT(tx_5); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_5, get_tx_version_from_events(events), stub_key, 0, CURRENCY_TO_KEY_OUT_RELAXED, true); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_5, get_tx_version_from_events(events), 0, stub_key, 0, CURRENCY_TO_KEY_OUT_RELAXED, true); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_5); @@ -1316,7 +1316,7 @@ bool multisig_and_unlock_time::generate(std::vector& events) c extra_expiration_time = AUTO_VAL_INIT(extra_expiration_time); extra_expiration_time.v = expiration_time; transaction tx_6 = AUTO_VAL_INIT(tx_6); - r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ extra_expiration_time }), empty_attachment, tx_6, get_tx_version_from_events(events), stub_key, 0, CURRENCY_TO_KEY_OUT_RELAXED, true); + r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ extra_expiration_time }), empty_attachment, tx_6, get_tx_version_from_events(events), 0, stub_key, 0, CURRENCY_TO_KEY_OUT_RELAXED, true); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); CHECK_AND_ASSERT_MES(get_tx_expiration_time(tx_6) == expiration_time, false, "Expiration time was not correctly set"); r = sign_multisig_input_in_tx(tx_6, tx_5_ms_out_idx, miner_acc.get_keys(), tx_5, &tx_fully_signed); @@ -1429,7 +1429,7 @@ bool multisig_and_coinbase::generate(std::vector& events) cons destinations.assign({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, bob_acc.get_public_address()) }); transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0); + r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); bool fully_signed_tx = false; r = sign_multisig_input_in_tx(tx_1, 0, alice_acc.get_keys(), blk_1.miner_tx, &fully_signed_tx); @@ -1459,7 +1459,7 @@ bool multisig_and_coinbase::generate(std::vector& events) cons r = fill_tx_sources_and_destinations(events, prev_block, miner_acc.get_keys(), ms_addr_list, blk_2_reward, TESTS_DEFAULT_FEE, 0, sources, destinations, false, false, 1); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction miner_tx = AUTO_VAL_INIT(miner_tx); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, miner_tx, get_tx_version_from_events(events), height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW, CURRENCY_TO_KEY_OUT_RELAXED, true); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, miner_tx, get_tx_version_from_events(events), 0, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW, CURRENCY_TO_KEY_OUT_RELAXED, true); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); // replace vin with coinbase input @@ -1477,7 +1477,7 @@ bool multisig_and_coinbase::generate(std::vector& events) cons r = generator.construct_block_manually(b, prev_block, miner_acc, test_generator::bf_miner_tx, 0, 0, 0, null_hash, 1, miner_tx); CHECK_AND_ASSERT_MES(r, false, "construct_block_manually failed"); } - events.push_back(blk_3); + ADD_CUSTOM_EVENT(events, blk_3); // rewind blocks to be able to spend mined money REWIND_BLOCKS_N(events, blk_3r, blk_3, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); @@ -1493,7 +1493,7 @@ bool multisig_and_coinbase::generate(std::vector& events) cons transaction tx_2 = AUTO_VAL_INIT(tx_2); r = construct_tx(alice_acc.get_keys(), std::vector({ se }), std::vector({ tx_destination_entry(se.amount - TESTS_DEFAULT_FEE, alice_acc.get_public_address()) }), - empty_attachment, tx_2, get_tx_version_from_events(events), 0); + empty_attachment, tx_2, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); r = sign_multisig_input_in_tx(tx_2, 0, alice_acc.get_keys(), blk_3.miner_tx, &fully_signed_tx); @@ -1638,7 +1638,7 @@ multisig_and_checkpoints::multisig_and_checkpoints() bool multisig_and_checkpoints::set_cp(currency::core& c, size_t ev_index, const std::vector& events) { currency::checkpoints checkpoints; - checkpoints.add_checkpoint(15, "fda3e645fbfd0f4852aa68e6ad021c9005c9faf2d7ba6b1b3c8e24efb9c0e8d0"); + checkpoints.add_checkpoint(15, "a78fa870608991aa773d5d5aaf684ac77fea30c3e103b00d3c05c15912215c31"); c.set_checkpoints(std::move(checkpoints)); return true; @@ -2259,7 +2259,7 @@ bool multisig_n_participants_seq_signing::generate(std::vector r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), ms_addr_list, ms_amount, TESTS_DEFAULT_FEE, 0, sources, destinations, true, true, m_minimum_signs_to_spend); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0, 0); events.push_back(tx_1); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1); @@ -2289,7 +2289,7 @@ bool multisig_n_participants_seq_signing::generate(std::vector // construct a transaction (no participants keys are provided, thus no signs for ms input are created) transaction tx = AUTO_VAL_INIT(tx); - r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx, get_tx_version_from_events(events), 0); + r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); // sign the transaction by (m_minimum_signs_to_spend) participants in random order diff --git a/tests/core_tests/offers_test.cpp b/tests/core_tests/offers_test.cpp index e9be6c2c..39c115ae 100644 --- a/tests/core_tests/offers_test.cpp +++ b/tests/core_tests/offers_test.cpp @@ -633,7 +633,7 @@ bool offer_removing_and_selected_output::generate(std::vector& std::vector sources; r = fill_tx_sources(sources, events, blk_0r, miner_acc.get_keys(), destinations_amount + TESTS_DEFAULT_FEE, 0); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed"); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_0); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); diff --git a/tests/core_tests/pos_basic_tests.cpp b/tests/core_tests/pos_basic_tests.cpp index 06fbf71a..c07a2850 100644 --- a/tests/core_tests/pos_basic_tests.cpp +++ b/tests/core_tests/pos_basic_tests.cpp @@ -174,7 +174,8 @@ bool pos_mining_with_decoys::generate(std::vector& events) con destinations.emplace_back(COIN, carol_acc.get_public_address()); transaction tx_0{}; - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_0); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index da3e08c1..a6e4cd4e 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -28,6 +28,7 @@ void pos_block_builder::step1_init_header(const hard_forks_descriptor& hardforks m_height = block_height; m_context.zarcanum = hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, m_height); + m_miner_tx_version = get_tx_version_and_hardfork_id(m_height, hardforks, m_miner_tx_hardfork_id); m_step = 1; } @@ -160,7 +161,6 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, { CHECK_AND_ASSERT_THROW_MES(m_step == 3, "pos_block_builder: incorrect step sequence"); - uint64_t tx_version = m_context.zarcanum ? TRANSACTION_VERSION_POST_HF4 : TRANSACTION_VERSION_PRE_HF4; pos_entry pe{}; pe.stake_unlock_time = 0; // TODO pe.amount = m_context.stake_amount; @@ -171,7 +171,8 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, size_t estimated_block_size = m_txs_total_size; m_block.miner_tx = transaction{}; bool r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, - reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use); + reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, m_miner_tx_version, m_miner_tx_hardfork_id, + extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use); CHECK_AND_ASSERT_THROW_MES(r, "construct_miner_tx failed"); estimated_block_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx); @@ -180,7 +181,8 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size, { m_block.miner_tx = transaction{}; r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee, - reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use); + reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, m_block_reward, m_miner_tx_version, m_miner_tx_hardfork_id, + extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use); CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed"); cumulative_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx); diff --git a/tests/core_tests/pos_block_builder.h b/tests/core_tests/pos_block_builder.h index fdf7a297..a0014f1e 100644 --- a/tests/core_tests/pos_block_builder.h +++ b/tests/core_tests/pos_block_builder.h @@ -76,6 +76,8 @@ struct pos_block_builder uint64_t m_total_fee = 0; //currency::stake_kernel m_stake_kernel {}; size_t m_height = 0; + size_t m_miner_tx_hardfork_id = 0; + uint64_t m_miner_tx_version = 0; size_t m_pos_stake_output_gindex = 0; uint64_t m_block_reward = 0; currency::tx_generation_context m_miner_tx_tgc {}; diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index 206a5596..9bff9d9b 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -42,17 +42,17 @@ bool test_transaction_generation_and_ring_signature() account_base rv_acc2; rv_acc2.generate(); transaction tx_mine_1; - construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().account_address, miner_acc1.get_keys().account_address, tx_mine_1, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4); + construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().account_address, miner_acc1.get_keys().account_address, tx_mine_1, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0); transaction tx_mine_2; - construct_miner_tx(0, 0, 0, 0, 0, miner_acc2.get_keys().account_address, miner_acc2.get_keys().account_address, tx_mine_2, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4); + construct_miner_tx(0, 0, 0, 0, 0, miner_acc2.get_keys().account_address, miner_acc2.get_keys().account_address, tx_mine_2, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0); transaction tx_mine_3; - construct_miner_tx(0, 0, 0, 0, 0, miner_acc3.get_keys().account_address, miner_acc3.get_keys().account_address, tx_mine_3, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4); + construct_miner_tx(0, 0, 0, 0, 0, miner_acc3.get_keys().account_address, miner_acc3.get_keys().account_address, tx_mine_3, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0); transaction tx_mine_4; - construct_miner_tx(0, 0, 0, 0, 0, miner_acc4.get_keys().account_address, miner_acc4.get_keys().account_address, tx_mine_4, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4); + construct_miner_tx(0, 0, 0, 0, 0, miner_acc4.get_keys().account_address, miner_acc4.get_keys().account_address, tx_mine_4, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0); transaction tx_mine_5; - construct_miner_tx(0, 0, 0, 0, 0, miner_acc5.get_keys().account_address, miner_acc5.get_keys().account_address, tx_mine_5, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4); + construct_miner_tx(0, 0, 0, 0, 0, miner_acc5.get_keys().account_address, miner_acc5.get_keys().account_address, tx_mine_5, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0); transaction tx_mine_6; - construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().account_address, miner_acc6.get_keys().account_address, tx_mine_6, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4); + construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().account_address, miner_acc6.get_keys().account_address, tx_mine_6, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0); //fill inputs entry typedef tx_source_entry::output_entry tx_output_entry; @@ -101,7 +101,7 @@ bool test_transaction_generation_and_ring_signature() transaction tx_rc1; std::vector attachments; - bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, attachments, tx_rc1, get_tx_version(0, hf), 0); + bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, attachments, tx_rc1, get_tx_version(0, hf), 0, 0); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); crypto::hash pref_hash = get_transaction_prefix_hash(tx_rc1); @@ -139,7 +139,7 @@ bool test_block_creation() uint64_t block_reward_without_fee = 0; uint64_t block_reward = 0; block b; - r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, adr, adr, b.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4); + r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, adr, adr, b.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0); return r; } diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 14b3db62..a0527f4a 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -1239,8 +1239,9 @@ bool tx_expiration_time::generate(std::vector& events) const std::vector destinations; r = fill_tx_sources_and_destinations(events, blk_2, alice_acc.get_keys(), bob_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); - transaction tx_2 = AUTO_VAL_INIT(tx_2); - r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_2, get_tx_version_from_events(events), 0); + transaction tx_2{}; + size_t tx_hardfork_id{}; + r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_2, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); set_tx_expiration_time(tx_2, ts_median + TX_EXPIRATION_MEDIAN_SHIFT + 1); // one second greather than minimum allowed r = resign_tx(alice_acc.get_keys(), sources, tx_2); @@ -1258,7 +1259,7 @@ bool tx_expiration_time::generate(std::vector& events) const r = fill_tx_sources_and_destinations(events, blk_3, alice_acc.get_keys(), bob_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_3 = AUTO_VAL_INIT(tx_3); - r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_3, get_tx_version_from_events(events), 0); + r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_attachment, tx_3, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); set_tx_expiration_time(tx_3, ts_median + TX_EXPIRATION_MEDIAN_SHIFT + 0); // exact expiration time, should not pass (see core condition above) r = resign_tx(alice_acc.get_keys(), sources, tx_3); @@ -1322,8 +1323,9 @@ bool tx_expiration_time_and_block_template::generate(std::vector destinations; bool r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); - transaction tx_1 = AUTO_VAL_INIT(tx_1); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_from_events(events), 0); + transaction tx_1{}; + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_1, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); uint64_t tx_1_expiration_time = ts_median + TX_EXPIRATION_MEDIAN_SHIFT + 1; // one second greather than minimum allowed set_tx_expiration_time(tx_1, tx_1_expiration_time); @@ -1394,8 +1396,9 @@ bool tx_expiration_time_and_chain_switching::generate(std::vector destinations; r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); - transaction tx_0 = AUTO_VAL_INIT(tx_0); - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + transaction tx_0{}; + size_t tx_hardfork_id{}; + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); uint64_t tx_0_expiration_time = ts_median + TX_EXPIRATION_MEDIAN_SHIFT + 0; // one second less than minimum allowed (see condition above) set_tx_expiration_time(tx_0, tx_0_expiration_time); @@ -1515,8 +1518,9 @@ bool tx_key_image_pool_conflict::generate(std::vector& events) std::vector destinations; r = fill_tx_sources_and_destinations(events, blk_0r, m_miner_acc.get_keys(), bob_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); - transaction tx_0 = AUTO_VAL_INIT(tx_0); - r = construct_tx(m_miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_from_events(events), 0); + transaction tx_0{}; + size_t tx_hardfork_id{}; + r = construct_tx(m_miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id), tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); LOG_PRINT_YELLOW("tx_0 = " << get_transaction_hash(tx_0), LOG_LEVEL_0); // do not push tx_0 into events yet @@ -1643,15 +1647,18 @@ bool tx_version_against_hardfork::generate(std::vector& events // tx_1 tx_1 is accepted uint64_t tx_version_good = 0, tx_version_bad = 0; + size_t tx_hardfork_id = 0; // select good and bad tx versions based on active hardfork size_t most_recent_hardfork_id = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_0r)); switch(most_recent_hardfork_id) { case ZANO_HARDFORK_04_ZARCANUM: + tx_hardfork_id = 0; case ZANO_HARDFORK_05: tx_version_good = TRANSACTION_VERSION_POST_HF4; tx_version_bad = TRANSACTION_VERSION_PRE_HF4; + tx_hardfork_id = ZANO_HARDFORK_05; break; default: LOG_ERROR("hardfork " << most_recent_hardfork_id << " is not supported by this test"); @@ -1667,7 +1674,7 @@ bool tx_version_against_hardfork::generate(std::vector& events r = fill_tx_sources_and_destinations(events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_0{}; - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version_good, 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version_good, tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); events.push_back(tx_0); MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0); @@ -1681,7 +1688,7 @@ bool tx_version_against_hardfork::generate(std::vector& events r = fill_tx_sources_and_destinations(events, blk_0, miner_acc.get_keys(), miner_acc.get_public_address(), MK_TEST_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources_and_destinations failed"); transaction tx_1{}; - r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version_bad, 0); + r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_attachment, tx_0, tx_version_bad, tx_hardfork_id, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); // check tx pool rejection DO_CALLBACK(events, "mark_invalid_tx"); @@ -2121,3 +2128,481 @@ bool tx_pool_semantic_validation::generate(std::vector& events return true; } + +input_refers_to_incompatible_by_type_output::input_refers_to_incompatible_by_type_output() +{ + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_htlc_input_refers_to_key_output_is_wrong); + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_to_key_input_refers_zarcanum_output_is_wrong); + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_htlc_input_refers_zarcanum_output_is_wrong); + REGISTER_CALLBACK_METHOD(input_refers_to_incompatible_by_type_output, assert_zc_input_refers_bare_output_is_wrong); + m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 14); +} + +bool input_refers_to_incompatible_by_type_output::generate(std::vector& events) const +{ + // Test idea: ensure that input and output compatibility checks work. + + GENERATE_ACCOUNT(miner); + MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); + + DO_CALLBACK(events, "configure_core"); + + REWIND_BLOCKS(events, blk_0r, blk_0, miner); + block& top{blk_0r}; + MAKE_TX_FEE(events, tx_00, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk_1, top, miner, tx_00); + top = blk_1; + } + + // An input of the type "txin_htlc" refers by a "ref_by_id" object to an output with a target of the type "txout_to_key". + { + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + transaction tx_1{}; + + top = blk; + + { + txin_htlc input{}; + + { + ref_by_id reference{}; + + reference.tx_id = get_transaction_hash(tx_0); + reference.n = get_tx_out_index_by_amount(tx_0, MK_TEST_COINS(7)); + CHECK_AND_ASSERT_NEQ(reference.n, UINT64_MAX); + input.key_offsets.push_back(reference); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + } + + input.k_image = crypto::point_t{{0x59, 0x01, 0xed, 0xcc, 0x3a, 0xe7, 0xaa, 0x83, 0x6c, 0x79, 0xfb, 0xed, 0x5d, 0x60, 0x02, 0xc5, 0xd0, 0xbf, 0x65, 0x85, 0x7b, 0x65, 0x25, 0x0e, 0x22, 0xcb, 0x63, + 0x64, 0x3b, 0x3b, 0x47, 0x30}}.to_key_image(); + input.amount = MK_TEST_COINS(7); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + { + tx_out_bare output_bare{}; + txout_to_key output_to_key{}; + + output_bare.amount = MK_TEST_COINS(2); + output_to_key.key = crypto::point_t{{0x2c, 0xdc, 0xc4, 0x7c, 0x38, 0x69, 0xe5, 0xe2, 0x4c, 0x5e, 0x10, 0xb2, 0xbe, 0x57, 0xe9, 0x42, 0x72, 0xd8, 0xf8, 0xb5, 0x97, 0xb9, 0x02, 0x41, 0xba, 0xea, + 0x82, 0xb3, 0xaf, 0x0c, 0xf0, 0x09}}.to_public_key(); + output_bare.target = output_to_key; + tx_1.vout.push_back(output_bare); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 1); + } + + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_to_key_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_htlc" refers by a global output index to an output with a target of the type "txout_to_key". + { + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + transaction tx_1{}; + + top = blk; + + { + txin_htlc input{}; + + { + uint64_t global_output_index{}; + + CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, get_tx_out_index_by_amount(tx_0, MK_TEST_COINS(7)), global_output_index), true); + CHECK_AND_ASSERT_NEQ(global_output_index, UINT64_MAX); + input.key_offsets.push_back(global_output_index); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + } + + input.k_image = crypto::point_t{{0xc6, 0x1c, 0xda, 0xf7, 0x9e, 0xb7, 0xd9, 0xc2, 0x46, 0x90, 0x29, 0xc8, 0x8a, 0x8f, 0xb4, 0x3e, 0x8e, 0xa8, 0x3b, 0x33, 0x4c, 0x75, 0xdf, 0xcb, 0x8b, 0x77, 0xf7, + 0x39, 0xa7, 0x17, 0xc9, 0xb4}}.to_key_image(); + input.amount = MK_TEST_COINS(7); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + { + tx_out_bare output_bare{}; + txout_to_key output_to_key{}; + + output_bare.amount = MK_TEST_COINS(2); + output_to_key.key = crypto::point_t{{0xc4, 0x17, 0xc7, 0x7f, 0xb2, 0x5d, 0xcb, 0x4b, 0x29, 0xdf, 0xea, 0x53, 0x70, 0x11, 0xbb, 0x42, 0x33, 0x0d, 0xf1, 0x22, 0x2d, 0xe4, 0x84, 0x24, 0x36, 0xc0, + 0x06, 0xd5, 0x8c, 0xf8, 0x23, 0x62}}.to_public_key(); + output_bare.target = output_to_key; + tx_1.vout.push_back(output_bare); + } + + tx_1.signatures.push_back(NLSAG_sig{{crypto::signature{}}}); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_to_key_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + DO_CALLBACK_PARAMS(events, "check_hardfork_inactive", size_t{ZANO_HARDFORK_04_ZARCANUM}); + + { + REWIND_BLOCKS_N(events, blk, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + top = blk; + } + + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_01, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_01); + top = blk; + } + + MAKE_TX_FEE(events, tx_02, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_02); + top = blk; + } + + // An input of the type "txin_to_key" refers by a "ref_by_id" object to an output of the type "tx_out_zarcanum". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS(events, blk_r, top, miner); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_to_key input{}; + + input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_0), 0}); + CHECK_AND_ASSERT_EQ(tx_0.vout.at(boost::get(input.key_offsets.front()).n).type(), typeid(tx_out_zarcanum)); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.k_image = crypto::point_t({0x59,0x01, 0xed, 0xcc, 0x3a, 0xe7, 0xaa, 0x83, 0x6c, 0x79, 0xfb, 0xed, 0x5d, 0x60, 0x02, 0xc5, 0xd0, 0xbf, 0x65, 0x85, 0x7b, 0x65, 0x25, 0x0e, 0x22, 0xcb, 0x63, + 0x64, 0x3b, 0x3b, 0x47, 0x30}).to_key_image(); + input.amount = MK_TEST_COINS(2); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_to_key_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_to_key" refers by a global output index to an output of the type "tx_out_zarcanum". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS(events, blk_r, top, miner); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_to_key input{}; + + { + uint64_t global_output_index{}; + + CHECK_AND_ASSERT_EQ(tx_0.vout.front().type(), typeid(tx_out_zarcanum)); + CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, 0, global_output_index), true); + input.key_offsets.push_back(global_output_index); + } + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.k_image = crypto::point_t{{0xbc, 0x2d, 0xdc, 0xc5, 0x93, 0x03, 0x9f, 0x0e, 0xce, 0x76, 0xee, 0xef, 0xd9, 0x1c, 0x2c, 0x3e, 0x8c, 0x4a, 0xca, 0x87, 0x9b, 0x6e, 0x3a, 0xda, 0xaf, 0x0c, + 0x92, 0x88, 0xda, 0x88, 0xc0, 0xf0}}.to_key_image(); + // A container is selected by an amount specified in an input. ZC outputs have .amount equals to 0. Thus, the input has .amount equals to 0. + input.amount = 0; + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_to_key_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_zc_input" refers by a "ref_by_id" object to an output with a target of the type "txout_to_key". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS(events, blk_r, top, miner); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_zc_input input{}; + + input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_00), 0}); + + { + const auto& output{tx_00.vout.at(boost::get(input.key_offsets.front()).n)}; + + CHECK_AND_ASSERT_EQ(output.type(), typeid(tx_out_bare)); + CHECK_AND_ASSERT_EQ(boost::get(output).target.type(), typeid(txout_to_key)); + } + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.key_offsets.emplace_back(ref_by_id{get_transaction_hash(tx_01), 0}); + + { + const auto& output{tx_01.vout.at(boost::get(input.key_offsets.at(1)).n)}; + + CHECK_AND_ASSERT_EQ(output.type(), typeid(tx_out_zarcanum)); + } + + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 2); + input.k_image = crypto::point_t{{0x31, 0x31, 0xd0, 0xf7, 0x13, 0x73, 0xff, 0x21, 0x14, 0xe8, 0x17, 0x4d, 0x18, 0x20, 0x12, 0x2d, 0x80, 0x31, 0xd5, 0x11, 0x82, 0xc0, 0x37, 0xad, 0xd2, 0x7b, 0x8c, + 0xf2, 0xdd, 0xd4, 0x34, 0x9a}}.to_key_image(); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_zc_input_refers_bare_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_htlc" refers by a "ref_by_id" object to an output of the type "tx_out_zarcanum". + { + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + { + REWIND_BLOCKS_N_WITH_TIME(events, blk_r, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_htlc input{}; + + input.key_offsets.push_back(ref_by_id{get_transaction_hash(tx_0), 0}); + CHECK_AND_ASSERT_EQ(tx_0.vout.at(boost::get(input.key_offsets.front()).n).type(), typeid(tx_out_zarcanum)); + input.k_image = crypto::point_t{{0x7b, 0xf5, 0x28, 0x09, 0xe8, 0x7e, 0x9c, 0x71, 0x0b, 0xad, 0x24, 0xa1, 0x9d, 0xb4, 0xc8, 0xd7, 0x96, 0x72, 0x18, 0xe6, 0x4b, 0x8f, 0x31, 0x01, 0xb0, 0x43, 0xa0, + 0xcc, 0xce, 0x72, 0x8c, 0x7e}}.to_key_image(); + input.amount = MK_TEST_COINS(2); + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + // An input of the type "txin_htlc" refers by a global output index to an output of the type "tx_out_zarcanum". + { + MAKE_TX_FEE(events, tx_0, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, top); + + { + MAKE_NEXT_BLOCK_TX1(events, blk, top, miner, tx_0); + top = blk; + } + + DO_CALLBACK_PARAMS(events, "check_hardfork_active", size_t{ZANO_HARDFORK_04_ZARCANUM}); + + { + REWIND_BLOCKS_N_WITH_TIME(events, blk_r, top, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + top = blk_r; + } + + transaction tx_1{}; + + tx_1.version = 2; + + { + txin_htlc input{}; + uint64_t global_output_index{}; + + CHECK_AND_ASSERT_EQ(tx_0.vout.front().type(), typeid(tx_out_zarcanum)); + CHECK_AND_ASSERT_EQ(find_global_index_for_output(events, get_block_hash(top), tx_0, 0, global_output_index), true); + input.key_offsets.push_back(global_output_index); + CHECK_AND_ASSERT_EQ(input.key_offsets.size(), 1); + input.k_image = crypto::point_t{{0xbc, 0x2d, 0xdc, 0xc5, 0x93, 0x03, 0x9f, 0x0e, 0xce, 0x76, 0xee, 0xef, 0xd9, 0x1c, 0x2c, 0x3e, 0x8c, 0x4a, 0xca, 0x87, 0x9b, 0x6e, 0x3a, 0xda, 0xaf, 0x0c, 0x92, + 0x88, 0xda, 0x88, 0xc0, 0xf0}}.to_key_image(); + // A container is selected by an amount specified in an input. ZC outputs have .amount equals to 0. Thus, the input has .amount equals to 0. + input.amount = 0; + tx_1.vin.push_back(input); + CHECK_AND_ASSERT_EQ(tx_1.vin.size(), 1); + } + + tx_1.vout.push_back(tx_out_zarcanum{}); + tx_1.vout.push_back(tx_out_zarcanum{}); + CHECK_AND_ASSERT_EQ(tx_1.vout.size(), 2); + tx_1.extra.push_back(zarcanum_tx_data_v1{TESTS_DEFAULT_FEE}); + CHECK_AND_ASSERT_EQ(tx_1.extra.size(), 1); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx_1); + DO_CALLBACK_PARAMS_STR(events, "assert_htlc_input_refers_zarcanum_output_is_wrong", t_serializable_object_to_blob(tx_1)); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_htlc_input_refers_to_key_output_is_wrong(const currency::core& c, size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_htlc)); + + { + uint64_t max_related_block_height{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height), false); + } + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_to_key_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_to_key)); + + { + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height, + source_max_unlock_time_for_pos_coinbase), false); + } + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_zc_input_refers_bare_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_zc_input)); + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), true); + } + + { + bool all_inputs_have_explicit_native_asset_id{}; + uint64_t max_related_block_height{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height, + all_inputs_have_explicit_native_asset_id), false); + } + + return true; +} + +bool input_refers_to_incompatible_by_type_output::assert_htlc_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const +{ + transaction tx{}; + + CHECK_AND_ASSERT_EQ(t_unserializable_object_from_blob(tx, boost::get(events.at(ev_index)).callback_params), true); + CHECK_AND_ASSERT_EQ(tx.vin.front().type(), typeid(txin_htlc)); + + { + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().check_tx_input(tx, 0, boost::get(tx.vin.front()), get_transaction_hash(tx), max_related_block_height, + source_max_unlock_time_for_pos_coinbase), false); + } + + { + std::vector keys{}; + uint64_t max_related_block_height{}; + uint64_t source_max_unlock_time_for_pos_coinbase{}; + + CHECK_AND_ASSERT_EQ(c.get_blockchain_storage().get_output_keys_for_input_with_checks(tx, tx.vin.front(), keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase), false); + } + + return true; +} diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 9888ee3e..6e3ae56e 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -165,3 +165,13 @@ struct tx_pool_semantic_validation : public test_chain_unit_enchanced { bool generate(std::vector& events) const; }; + +struct input_refers_to_incompatible_by_type_output : public test_chain_unit_enchanced +{ + input_refers_to_incompatible_by_type_output(); + bool generate(std::vector& events) const; + bool assert_htlc_input_refers_to_key_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; + bool assert_to_key_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; + bool assert_zc_input_refers_bare_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; + bool assert_htlc_input_refers_zarcanum_output_is_wrong(const currency::core& c, const size_t ev_index, const std::vector& events) const; +}; diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 79eb631d..e3039a06 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1661,7 +1661,9 @@ bool gen_wallet_alias_and_unconfirmed_txs::generate(std::vector({ ai }), empty_attachment, tx_alice_alias, get_tx_version_from_events(events), sk, 0); + size_t tx_hardfork_id{}; + uint64_t tx_version = get_tx_version_and_harfork_id_from_events(events, tx_hardfork_id); + r = construct_tx(miner_acc.get_keys(), sources, destinations, std::vector({ ai }), empty_attachment, tx_alice_alias, tx_version, tx_hardfork_id, sk, 0); CHECK_AND_ASSERT_MES(r, false, "construct_tx failed"); ADD_CUSTOM_EVENT(events, tx_alice_alias); @@ -2306,7 +2308,7 @@ bool generate_oversized_offer(size_t min_size, size_t max_size, bc_services::off // construct fake tx to estimate it's size transaction tx = AUTO_VAL_INIT(tx); crypto::secret_key one_time_secret_key; - if (!construct_tx(account_keys(), std::vector(), std::vector(), empty_extra, att_container, tx, tx_version, one_time_secret_key, 0, 0, true, 0)) + if (!construct_tx(account_keys(), std::vector(), std::vector(), empty_extra, att_container, tx, tx_version, 0, one_time_secret_key, 0, 0, true, 0)) return false; size_t sz = get_object_blobsize(tx); diff --git a/tests/core_tests/zarcanum_test.cpp b/tests/core_tests/zarcanum_test.cpp index 72dea5b4..472d3315 100644 --- a/tests/core_tests/zarcanum_test.cpp +++ b/tests/core_tests/zarcanum_test.cpp @@ -520,7 +520,8 @@ bool zarcanum_txs_with_big_shuffled_decoy_set_shuffled::generate(std::vector #include +#include using namespace std; #ifndef KECCAKF_ROUNDS diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 9b285b68..c03eb834 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -56,6 +56,8 @@ void test_plain_wallet() epee::misc_utils::sleep_no_w(2000); res = plain_wallet::sync_call("reset_connection_url", 0, "195.201.107.230:33336"); + //res = plain_wallet::sync_call("reset_connection_url", 0, "https://node.zano.org:443"); + r = plain_wallet::sync_call("run_wallet", instance_id, ""); while(true) diff --git a/tests/performance_tests/single_tx_test_base.h b/tests/performance_tests/single_tx_test_base.h index a605d624..a3aff814 100644 --- a/tests/performance_tests/single_tx_test_base.h +++ b/tests/performance_tests/single_tx_test_base.h @@ -20,7 +20,7 @@ public: uint64_t block_reward_without_fee = 0; 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)) + 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, 0, 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/get_xtype_from_string.cpp b/tests/unit_tests/get_xtype_from_string.cpp index 5bcb74df..0a520c16 100644 --- a/tests/unit_tests/get_xtype_from_string.cpp +++ b/tests/unit_tests/get_xtype_from_string.cpp @@ -151,10 +151,10 @@ TEST_neg(int16_t, "+32768"); // 2^15 TEST_neg(int16_t, "-32769"); // -2^15 - 1 TEST_neg(int16_t, ""); -TEST_pos(int32_t, 2'147'483'647, "2147483647"); // 2^31 - 1 -TEST_pos(int32_t, -2'147'483'648, "-2147483648"); // -2^31 -TEST_pos(int32_t, 0, "-0"); -TEST_pos(int32_t, 0, "+0"); +TEST_pos(int32_t, 2'147'483'647, "2147483647"); // 2^31 - 1 +TEST_pos(int32_t, -2'147'483'647 - 1, "-2147483648"); // -2^31 +TEST_pos(int32_t, 0, "-0"); +TEST_pos(int32_t, 0, "+0"); TEST_neg(int32_t, "-2147483649"); TEST_neg(int32_t, "2147483648"); diff --git a/tests/unit_tests/multiassets_test.cpp b/tests/unit_tests/multiassets_test.cpp index ad637b01..533d8826 100644 --- a/tests/unit_tests/multiassets_test.cpp +++ b/tests/unit_tests/multiassets_test.cpp @@ -245,7 +245,7 @@ static std::optional deserialize(serialization_metho return {}; } -static std::string get_string_presentation(const std::string& data) +[[maybe_unused]] static std::string get_string_presentation(const std::string& data) { std::string presentation{}; diff --git a/tests/unit_tests/test_format_utils.cpp b/tests/unit_tests/test_format_utils.cpp index f12c149f..b42a45f3 100644 --- a/tests/unit_tests/test_format_utils.cpp +++ b/tests/unit_tests/test_format_utils.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2014-2024 Zano 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. @@ -16,7 +17,7 @@ TEST(parse_and_validate_tx_extra, is_correct_parse_and_validate_tx_extra) currency::blobdata b = "dsdsdfsdfsf"; uint64_t block_reward_without_fee = 0, block_reward = 0; bool r = currency::construct_miner_tx(0, 0, 10000000000000, 1000, TESTS_DEFAULT_FEE, acc.get_keys().account_address, acc.get_keys().account_address, tx, - block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, b, 1); + block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0, b, 1); ASSERT_TRUE(r); crypto::public_key tx_pub_key; r = currency::parse_and_validate_tx_extra(tx, tx_pub_key); @@ -30,7 +31,7 @@ TEST(parse_and_validate_tx_extra, is_correct_extranonce_too_big) currency::blobdata b(260, 0); uint64_t block_reward_without_fee = 0, block_reward = 0; bool r = currency::construct_miner_tx(0, 0, 10000000000000, 1000, TESTS_DEFAULT_FEE, acc.get_keys().account_address, acc.get_keys().account_address, tx, - block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, b, 1); + block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, 0, b, 1); ASSERT_FALSE(r); } diff --git a/utils/docker/remote-node-mobile/Dockerfile b/utils/docker/remote-node-mobile/Dockerfile new file mode 100644 index 00000000..0d08e778 --- /dev/null +++ b/utils/docker/remote-node-mobile/Dockerfile @@ -0,0 +1,160 @@ +########################################################################################### +## zanod Dockerfile +########################################################################################### + +# +# Usage: +# (make sure you have correct permission for /var/data/zano-data prior to run!) +# +# docker run --restart=always -v /var/data/zano-data:/home/zano/.Zano -p 11121:11121 -p 11211:11211 --name=zanod -dit zanoproject/remote-note +# +# To get into container and interact with the daemon: +# docker attach zanod +# +# To detach from container and left it running: +# Ctrl+P, Ctrl+Q +# +# To stop container: +# docker stop zanod +# +# To build with different lib versions, pass through --build-arg's +# docker build --build-arg OPENSSL_VERSION_DOT=1.1.1n --build-arg OPENSSL_HASH=40dceb51a4f6a5275bde0e6bf20ef4b91bfc32ed57c0552e2e8e15463372b17a -f utils/docker/Dockerfile . +# +# Available Build Args +# - CMake Version: CMAKE_VERSION_DOT, CMAKE_HASH +# - Boost Version: BOOST_VERSION, BOOST_VERSION_DOT, BOOST_HASH +# - OpenSSL Version: OPENSSL_VERSION_DOT, OPENSSL_HASH + +# +# Build Zano +# + +FROM ubuntu:18.04 as build-prep + +ENV DEBIAN_FRONTEND noninteractive + +RUN apt update && \ + apt install -y build-essential \ + libicu-dev \ + libz-dev \ + curl \ + gcc-8 \ + g++-8 \ + git + +RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 700 --slave /usr/bin/g++ g++ /usr/bin/g++-7 && \ + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8 + +WORKDIR /root + +# Lib Settings +ARG CMAKE_VERSION_DOT=3.16.9 +ARG CMAKE_HASH=d71eda07d6ecf3964de65a0e36d0b171565e1aced56ba9f53ca3783406b5cacf + +ARG BOOST_VERSION=1_84_0 +ARG BOOST_VERSION_DOT=1.84.0 +ARG BOOST_HASH=cc4b893acf645c9d4b698e9a0f08ca8846aa5d6c68275c14c3e7949c24109454 + +ARG OPENSSL_VERSION_DOT=1.1.1w +ARG OPENSSL_HASH=cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8 + +# Environment Variables +ENV BOOST_ROOT /root/boost_${BOOST_VERSION} +ENV OPENSSL_ROOT_DIR=/root/openssl + +########################################################## +# Split download & compile to use dockers caching layers # +########################################################## + +# Download CMake +RUN set -ex \ + && curl https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION_DOT}/cmake-${CMAKE_VERSION_DOT}-Linux-x86_64.sh -OL\ + && echo "${CMAKE_HASH} cmake-${CMAKE_VERSION_DOT}-Linux-x86_64.sh" | sha256sum -c + +# Download Boost +RUN set -ex \ + && curl -L -o boost_${BOOST_VERSION}.tar.bz2 https://downloads.sourceforge.net/project/boost/boost/${BOOST_VERSION_DOT}/boost_${BOOST_VERSION}.tar.bz2 \ + && sha256sum boost_${BOOST_VERSION}.tar.bz2 \ + && echo "${BOOST_HASH} boost_${BOOST_VERSION}.tar.bz2" | sha256sum -c\ + && tar -xvf boost_${BOOST_VERSION}.tar.bz2 + + +# Download OpenSSL +RUN curl https://www.openssl.org/source/openssl-${OPENSSL_VERSION_DOT}.tar.gz -OL \ + && sha256sum openssl-${OPENSSL_VERSION_DOT}.tar.gz \ + && echo "${OPENSSL_HASH} openssl-${OPENSSL_VERSION_DOT}.tar.gz" | sha256sum -c + + +# Compile CMake +RUN set -ex \ + && mkdir /opt/cmake \ + && sh cmake-3.16.9-Linux-x86_64.sh --prefix=/opt/cmake --skip-license\ + && ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake\ + && cmake --version\ + && rm cmake-3.16.9-Linux-x86_64.sh + +# Compile Boost +RUN set -ex \ + && cd boost_${BOOST_VERSION} \ + && ./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer,log \ + && ./b2 + +# Compile OpenSSL +RUN set -ex \ + && tar xaf openssl-${OPENSSL_VERSION_DOT}.tar.gz \ + && rm openssl-${OPENSSL_VERSION_DOT}.tar.gz \ + && cd openssl-${OPENSSL_VERSION_DOT} \ + && ./config --prefix=/root/openssl --openssldir=/root/openssl shared zlib \ + && make \ + && make test \ + && make install \ + && cd .. \ + && rm -rf openssl-${OPENSSL_VERSION_DOT} + +FROM build-prep as build + +# Zano + +RUN pwd && mem_avail_gb=$(( $(getconf _AVPHYS_PAGES) * $(getconf PAGE_SIZE) / (1024 * 1024 * 1024) )) &&\ + make_job_slots=$(( $mem_avail_gb < 4 ? 1 : $mem_avail_gb / 4)) &&\ + echo make_job_slots=$make_job_slots &&\ + set -x &&\ + git clone --single-branch --recursive https://github.com/hyle-team/zano.git &&\ + cd zano &&\ + mkdir build && cd build &&\ + cmake -D STATIC=TRUE .. &&\ + make -j $make_job_slots daemon simplewallet + + +# +# Run Zano +# + +FROM ubuntu:18.04 + +# Install dependencies and Nginx +RUN apt update && apt install -y \ + nginx \ + curl \ + && apt clean + +RUN useradd -ms /bin/bash zano &&\ + mkdir -p /home/zano/.Zano &&\ + chown -R zano:zano /home/zano/.Zano + +USER zano:zano + +WORKDIR /home/zano +COPY --chown=zano:zano --from=build /root/zano/build/src/zanod . +COPY --chown=zano:zano --from=build /root/zano/build/src/simplewallet . + +# Copy Nginx configuration +USER root +COPY nginx.conf /etc/nginx/nginx.conf + +# blockchain loaction +VOLUME /home/zano/.Zano + +EXPOSE 11121 11211 33340 + +CMD service nginx start && ./zanod --disable-upnp --log-level=0 diff --git a/utils/docker/remote-node-mobile/nginx.conf b/utils/docker/remote-node-mobile/nginx.conf new file mode 100644 index 00000000..245e8ed9 --- /dev/null +++ b/utils/docker/remote-node-mobile/nginx.conf @@ -0,0 +1,73 @@ +events {} + +http { + + ## + # Basic Settings + ## + + limit_conn_zone $binary_remote_addr zone=addr:10m; + limit_req_zone $binary_remote_addr zone=global_limit:10m rate=10r/s; + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + # server_tokens off; + + # server_names_hash_bucket_size 64; + # server_name_in_redirect off; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + ## + # SSL Settings + ## + + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE + ssl_prefer_server_ciphers on; + + ## + # Logging Settings + ## + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + ## + # Gzip Settings + ## + + gzip on; + + include /etc/nginx/conf.d/*.conf; + include /etc/nginx/sites-enabled/*; + + + #mainnet + server { + listen 33340; + listen [::]:33340; + + # Apply globally to all locations + limit_req zone=global_limit burst=20 nodelay; + limit_conn addr 30; + + access_log /var/log/nginx/reverse-access.log; + error_log /var/log/nginx/reverse-error.log; + + + location /general_info + { + root /home/mobile_app_config; + add_header Cache-Control no-cache; + # set the Expires header to 31 December 2037 23:59:59 GMT, and the Cache-Control max-age to 10 years + expires 1s; + } + + location ~ ^/(json_rpc|getheight|gettransactions|sendrawtransaction|force_relay|getinfo|getblocks\.bin|get_o_indexes\.bin|get_o_indexes\.bin|getrandom_outs\.bin|getrandom_outs1\.bin|getrandom_outs2\.bin|getrandom_outs3\.bin|set_maintainers_info\.bin|get_tx_pool\.bin|check_keyimages\.bin|get_pos_details\.bin) { + proxy_pass http://127.0.0.1:11211$uri; + } + } +} diff --git a/utils/docker/Dockerfile b/utils/docker/zano-full-node/Dockerfile similarity index 100% rename from utils/docker/Dockerfile rename to utils/docker/zano-full-node/Dockerfile