diff --git a/.gitignore b/.gitignore index 04985b7f..7518f4e9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ ._.DS_Store Thumbs.db ._* -.idea \ No newline at end of file +.idea +.vs/* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dcee61e..a151f1ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,7 +102,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() if(MSVC) - add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /D__SSE4_1__") + add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0") add_compile_options(/bigobj /Zm1000 /Z7 /MP2 /W3 /GS- /wd4996 /wd4503 /wd4345 /wd4091 /FIinline_c.h) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib crypt32.lib") if(STATIC) @@ -224,7 +224,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") elseif(APPLE) find_package(Boost 1.71 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale) else() - find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale) + find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale log) endif() @@ -246,7 +246,7 @@ elseif(NOT MSVC) endif() if(BUILD_GUI) - cmake_minimum_required(VERSION 3.5) + cmake_minimum_required(VERSION 3.1) find_package(Qt5Widgets REQUIRED) endif() diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index 601672d5..a3220829 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -28,7 +28,7 @@ endif() set_property(TARGET upnpc-static mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat PROPERTY FOLDER "unused") if(MSVC) - set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused") + #set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused") endif() diff --git a/contrib/db/libmdbx/src/CMakeLists.txt b/contrib/db/libmdbx/src/CMakeLists.txt index 04aead5f..7dfc94aa 100644 --- a/contrib/db/libmdbx/src/CMakeLists.txt +++ b/contrib/db/libmdbx/src/CMakeLists.txt @@ -45,61 +45,6 @@ if(CC_HAS_VISIBILITY AND (LTO_ENABLED OR INTERPROCEDURAL_OPTIMIZATION)) set_target_properties(mdbx PROPERTIES LINK_FLAGS "-fvisibility=hidden") endif() -if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if(MSVC) - if(NOT MSVC_LIB_EXE) - # Find lib.exe - get_filename_component(CL_NAME ${CMAKE_C_COMPILER} NAME) - string(REPLACE cl.exe lib.exe MSVC_LIB_EXE ${CL_NAME}) - find_program(MSVC_LIB_EXE ${MSVC_LIB_EXE}) - endif() - if(MSVC_LIB_EXE) - message(STATUS "Found MSVC's lib tool: ${MSVC_LIB_EXE}") - set(MDBX_NTDLL_EXTRA_IMPLIB ${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.lib) - add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB} - COMMENT "Create extra-import-library for ntdll.dll" - MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" - COMMAND ${MSVC_LIB_EXE} /def:"${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" /out:"${MDBX_NTDLL_EXTRA_IMPLIB}" ${INITIAL_CMAKE_STATIC_LINKER_FLAGS}) - else() - message(SEND_ERROR "MSVC's lib tool not found") - endif() - elseif(MINGW OR MINGW64) - if(NOT DLLTOOL) - # Find dlltool - get_filename_component(GCC_NAME ${CMAKE_C_COMPILER} NAME) - string(REPLACE gcc dlltool DLLTOOL_NAME ${GCC_NAME}) - find_program(DLLTOOL NAMES ${DLLTOOL_NAME}) - endif() - if(DLLTOOL) - message(STATUS "Found dlltool: ${DLLTOOL}") - set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.a") - add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB} - COMMENT "Create extra-import-library for ntdll.dll" - MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" - COMMAND ${DLLTOOL} -d "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}") - else() - message(SEND_ERROR "dlltool not found") - endif() - endif() -endif() - -target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ${CMAKE_THREAD_LIBS_INIT}) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll.lib) - if(MDBX_NTDLL_EXTRA_IMPLIB) - # LY: Sometimes Cmake requires a nightmarish magic for simple things. - # 1) create a target out of the library compilation result - add_custom_target(ntdll_extra_target DEPENDS ${MDBX_NTDLL_EXTRA_IMPLIB}) - # 2) create an library target out of the library compilation result - add_library(ntdll_extra STATIC IMPORTED GLOBAL) - add_dependencies(ntdll_extra ntdll_extra_target) - # 3) specify where the library is (and where to find the headers) - set_target_properties(ntdll_extra - PROPERTIES - IMPORTED_LOCATION ${MDBX_NTDLL_EXTRA_IMPLIB}) - target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll_extra) - endif() -endif() set_target_properties(mdbx PROPERTIES INTERPROCEDURAL_OPTIMIZATION $ diff --git a/contrib/epee/include/misc_language.h b/contrib/epee/include/misc_language.h index c1c0c794..5855d977 100644 --- a/contrib/epee/include/misc_language.h +++ b/contrib/epee/include/misc_language.h @@ -509,6 +509,10 @@ namespace misc_utils } } + void UNSUBSCRIBE_ALL() + { + m_callbacks.clear(); + } template void RAISE_DEBUG_EVENT(const param_t& p) diff --git a/src/common/callstack_helper.cpp b/src/common/callstack_helper.cpp index 74bcc557..b84fe5a8 100644 --- a/src/common/callstack_helper.cpp +++ b/src/common/callstack_helper.cpp @@ -137,11 +137,17 @@ namespace tools STACKFRAME64 frame; memset(&frame, 0, sizeof frame); +#ifndef _M_ARM64 frame.AddrPC.Offset = context.Rip; +#endif frame.AddrPC.Mode = AddrModeFlat; +#ifndef _M_ARM64 frame.AddrStack.Offset = context.Rsp; +#endif frame.AddrStack.Mode = AddrModeFlat; +#ifndef _M_ARM64 frame.AddrFrame.Offset = context.Rbp; +#endif frame.AddrFrame.Mode = AddrModeFlat; IMAGEHLP_LINE64 line = { 0 }; diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp index 0474f9cd..a7b9a5ff 100644 --- a/src/common/command_line.cpp +++ b/src/common/command_line.cpp @@ -37,6 +37,7 @@ namespace command_line const arg_descriptor arg_no_predownload ( "no-predownload", "Do not pre-download blockchain database"); const arg_descriptor arg_force_predownload ( "force-predownload", "Pre-download blockchain database regardless of it's status"); + const arg_descriptor arg_process_predownload_from_path("predownload-from-local-path", "Instead of downloading file use downloaded local file"); const arg_descriptor arg_validate_predownload ( "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database"); const arg_descriptor arg_predownload_link ( "predownload-link", "Override url for blockchain database pre-downloading"); diff --git a/src/common/command_line.h b/src/common/command_line.h index 2c147d20..905b1067 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -229,6 +229,7 @@ namespace command_line extern const arg_descriptor arg_db_engine; extern const arg_descriptor arg_no_predownload; extern const arg_descriptor arg_force_predownload; + extern const arg_descriptor arg_process_predownload_from_path; extern const arg_descriptor arg_validate_predownload; extern const arg_descriptor arg_predownload_link; extern const arg_descriptor arg_deeplink; diff --git a/src/common/crypto_serialization.h b/src/common/crypto_serialization.h index 0b8bd62e..dd988a68 100644 --- a/src/common/crypto_serialization.h +++ b/src/common/crypto_serialization.h @@ -104,15 +104,15 @@ namespace crypto FIELD((std::vector&)(r_x)) FIELD(K1) FIELD(K2) - END_SERIALIZE() + END_SERIALIZE() - BEGIN_BOOST_SERIALIZATION() + BEGIN_BOOST_SERIALIZATION() BOOST_SERIALIZE(c) BOOST_SERIALIZE((std::vector&)(r_g)) BOOST_SERIALIZE((std::vector&)(r_x)) BOOST_SERIALIZE(K1) BOOST_SERIALIZE(K2) - END_BOOST_SERIALIZATION() + END_BOOST_SERIALIZATION() }; struct CLSAG_GGXXG_signature_serialized : public CLSAG_GGXXG_signature @@ -183,6 +183,21 @@ namespace crypto END_BOOST_SERIALIZATION() }; + struct generic_double_schnorr_sig_s : public generic_double_schnorr_sig + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD(y0) + FIELD(y1) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE(y0) + BOOST_SERIALIZE(y1) + END_BOOST_SERIALIZATION() + }; + struct BGE_proof_s : public BGE_proof { BEGIN_SERIALIZE_OBJECT() diff --git a/src/common/pre_download.h b/src/common/pre_download.h index e9aecf5b..ec12df55 100644 --- a/src/common/pre_download.h +++ b/src/common/pre_download.h @@ -21,8 +21,8 @@ namespace tools }; #ifndef TESTNET - static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2390000.pak", "ffc8d2220a4d8b3fba51073a422cbb6139c60858469ea086623f9d16329eb5b4", 2767268964, 5368627200 }; - static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2390000.pak", "7e58951bc523eb12e0ec07171bc67b3f96bad4d5454dd2da56f642a872e230d3", 3618283035, 5156397056 }; + static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2500000.pak", "8ffa2cb4213f4f96f97033c65a9e52bc350f683237808597784e79b24d5bfee7", 3242348793, 5905489920 }; + static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2500000.pak", "5509650e12c8f901e6731a2bfaf3abfd64409e3e1366d3d94cd11db8beddb0c3", 4239505801, 5893566464 }; #else static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 }; static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 }; @@ -50,6 +50,7 @@ namespace tools boost::system::error_code ec; uint64_t sz = boost::filesystem::file_size(db_main_file_path, ec); + if (ec) sz = 0; bool flag_force_predownload = command_line::has_arg(vm, command_line::arg_force_predownload); if (pre_download.unpacked_size == 0 || !(ec || (pre_download.unpacked_size > sz && pre_download.unpacked_size - sz > pre_download_min_size_difference) || flag_force_predownload) ) { @@ -59,53 +60,59 @@ namespace tools // okay, let's download - std::string downloading_file_path = db_main_file_path + ".download"; - - LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0); - epee::net_utils::http::interruptible_http_client cl; - - crypto::stream_cn_hash hash_stream; - auto last_update = std::chrono::system_clock::now(); - - auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes) + if (!command_line::has_arg(vm, command_line::arg_process_predownload_from_path)) { - if (cb_should_stop(total_bytes, received_bytes)) + + LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0); + epee::net_utils::http::interruptible_http_client cl; + + crypto::stream_cn_hash hash_stream; + auto last_update = std::chrono::system_clock::now(); + + auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes) { - LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0); - return false; + if (cb_should_stop(total_bytes, received_bytes)) + { + LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0); + return false; + } + + hash_stream.update(buff.data(), buff.size()); + + auto dif = std::chrono::system_clock::now() - last_update; + if (dif >= std::chrono::milliseconds(300)) + { + boost::io::ios_flags_saver ifs(std::cout); + std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r"; + last_update = std::chrono::system_clock::now(); + } + + return true; + }; + + tools::create_directories_if_necessary(working_folder); + r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */); + if (!r) + { + LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0); + return !flag_force_predownload; // fatal error only if force-predownload } - hash_stream.update(buff.data(), buff.size()); - - auto dif = std::chrono::system_clock::now() - last_update; - if (dif >= std::chrono::milliseconds(300)) + crypto::hash data_hash = hash_stream.calculate_hash(); + if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash) { - boost::io::ios_flags_saver ifs(std::cout); - std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r"; - last_update = std::chrono::system_clock::now(); + LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash); + return !flag_force_predownload; // fatal error only if force-predownload } - return true; - }; - - tools::create_directories_if_necessary(working_folder); - r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */); - if (!r) - { - LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0); - return !flag_force_predownload; // fatal error only if force-predownload + LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct", LOG_LEVEL_0); } - - crypto::hash data_hash = hash_stream.calculate_hash(); - if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash) + else { - LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash); - return !flag_force_predownload; // fatal error only if force-predownload + downloading_file_path = command_line::get_arg(vm, command_line::arg_process_predownload_from_path); } - LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct" , LOG_LEVEL_0); - if (!command_line::has_arg(vm, command_line::arg_validate_predownload)) { boost::filesystem::remove(db_main_file_path, ec); @@ -138,11 +145,14 @@ namespace tools std::string path_to_temp_blockchain_file = path_to_temp_blockchain + "/" + dbbs.get_db_main_file_name(); tools::create_directories_if_necessary(path_to_temp_blockchain); - boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec); - if (ec) + if (downloading_file_path != path_to_temp_blockchain_file) { - LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file); - return false; + boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec); + if (ec) + { + LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file); + return false; + } } // remove old blockchain database from disk @@ -180,6 +190,28 @@ namespace tools r = target_core.init(target_core_vm); CHECK_AND_ASSERT_MES(r, false, "Failed to init target core"); + if (true/*TODO: copnfigure with command line option*/) + { + //set checkpoints + { + currency::checkpoints checkpoints; + bool res = currency::create_checkpoints(checkpoints); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints"); + res = source_core.set_checkpoints(std::move(checkpoints)); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); + } + { + currency::checkpoints checkpoints; + bool res = currency::create_checkpoints(checkpoints); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints"); + res = target_core.set_checkpoints(std::move(checkpoints)); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); + } + } + + + + CHECK_AND_ASSERT_MES(target_core.get_top_block_height() == 0, false, "Target blockchain initialized not empty"); uint64_t total_blocks = source_core.get_current_blockchain_size(); diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp index 710692bd..07528c56 100644 --- a/src/connectivity_tool/conn_tool.cpp +++ b/src/connectivity_tool/conn_tool.cpp @@ -411,7 +411,8 @@ 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; - construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations); + 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); currency::blobdata txb = tx_to_blob(bl.miner_tx); //self validate block diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index d7261870..2f31c826 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -1166,6 +1166,11 @@ namespace crypto return scalar_t(crypto::cn_fast_hash(str.c_str(), str.size())); // will reduce mod L } + static hash h(const std::string& str) + { + return crypto::cn_fast_hash(str.c_str(), str.size()); + } + struct hs_t { hs_t(size_t size_to_reserve = 0) diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c index 87423fb8..2909f319 100644 --- a/src/crypto/tree-hash.c +++ b/src/crypto/tree-hash.c @@ -8,7 +8,9 @@ #include #include "hash-ops.h" - +#ifdef _M_ARM64 + #include "malloc.h" +#endif void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) { assert(count > 0); if (count == 1) { diff --git a/src/crypto/zarcanum.h b/src/crypto/zarcanum.h index b73cabf1..3fe4b5c1 100644 --- a/src/crypto/zarcanum.h +++ b/src/crypto/zarcanum.h @@ -1,5 +1,5 @@ -// Copyright (c) 2022-2023 Zano Project -// Copyright (c) 2022-2023 sowle (val@zano.org, crypto.sowle@gmail.com) +// Copyright (c) 2022-2024 Zano Project +// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com) // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -84,46 +84,47 @@ namespace crypto scalar_t y; }; - template + + template + inline bool generate_schnorr_sig_custom_generator(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result, const generator_t& g_point_g) + { +#ifndef NDEBUG + if (A != secret_a * g_point_g) + return false; +#endif + scalar_t r = scalar_t::random(); + point_t R = r * g_point_g; + hash_helper_t::hs_t hsc(3); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(R); + result.c = hsc.calc_hash(); + result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a + return true; + } + + template inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result); template<> inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result) { -#ifndef NDEBUG - if (A != secret_a * c_point_G) - return false; -#endif - scalar_t r = scalar_t::random(); - point_t R = r * c_point_G; - hash_helper_t::hs_t hsc(3); - hsc.add_hash(m); - hsc.add_point(A); - hsc.add_point(R); - result.c = hsc.calc_hash(); - result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a - return true; + return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_G); } template<> inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result) { -#ifndef NDEBUG - if (A != secret_a * c_point_X) - return false; -#endif - scalar_t r = scalar_t::random(); - point_t R = r * c_point_X; - hash_helper_t::hs_t hsc(3); - hsc.add_hash(m); - hsc.add_point(A); - hsc.add_point(R); - result.c = hsc.calc_hash(); - result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a - return true; + return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_X); } - template + inline bool generate_schnorr_sig(const hash& m, const public_key& A, const secret_key& secret_a, generic_schnorr_sig& result) + { + return generate_schnorr_sig(m, point_t(A), scalar_t(secret_a), result); + } + + + template inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept; // TODO @#@# make optimized version inline bool verify_schnorr_sig(const hash& m, const point_t& A, const generic_schnorr_sig& sig) noexcept; @@ -167,6 +168,110 @@ namespace crypto } } + // -------------------------------------------- + + // multi-base Schnorr-like proof (two generators, two secrets, one Fiat-Shamir challenge) + struct generic_double_schnorr_sig + { + scalar_t c; + scalar_t y0; + scalar_t y1; + }; + + template + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result); + + template<> + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result) + { +#ifndef NDEBUG + if (A != secret_a * c_point_G || B != secret_b * c_point_G) + return false; +#endif + scalar_t r0 = scalar_t::random(); + scalar_t r1 = scalar_t::random(); + point_t R0 = r0 * c_point_G; + point_t R1 = r1 * c_point_G; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(B); + hsc.add_point(R0); + hsc.add_point(R1); + result.c = hsc.calc_hash(); + result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a + result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b + return true; + } + + template<> + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result) + { +#ifndef NDEBUG + if (A != secret_a * c_point_X || B != secret_b * c_point_G) + return false; +#endif + scalar_t r0 = scalar_t::random(); + scalar_t r1 = scalar_t::random(); + point_t R0 = r0 * c_point_X; + point_t R1 = r1 * c_point_G; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(B); + hsc.add_point(R0); + hsc.add_point(R1); + result.c = hsc.calc_hash(); + result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a + result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b + return true; + } + + template + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept; + + template<> + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced()) + return false; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_pub_key(B); + hsc.add_point(A.mul_plus_G(sig.c, sig.y0)); // sig.y0 * G + sig.c * A + hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + + template<> + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced()) + return false; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_pub_key(B); + hsc.add_point(sig.y0 * c_point_X + sig.c * A); + hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + // TODO: improve this proof using random weightning factor struct vector_UG_aggregation_proof @@ -187,4 +292,4 @@ namespace crypto const vector_UG_aggregation_proof& sig, uint8_t* p_err = nullptr) noexcept; -} // namespace crypto +} // namespace crypto \ No newline at end of file diff --git a/src/currency_core/bc_attachments_helpers_basic.h b/src/currency_core/bc_attachments_helpers_basic.h index 18a8e558..74039e9d 100644 --- a/src/currency_core/bc_attachments_helpers_basic.h +++ b/src/currency_core/bc_attachments_helpers_basic.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,14 +8,54 @@ namespace bc_services { + template + struct is_boost_variant : std::false_type {}; + + template + struct is_boost_variant> : std::true_type {}; + + template + struct type_selector; + + template<> + struct type_selector + { + template + static const std::type_info& get_type(const t_type& t) + { + return t.type(); + } + template + static const t_return_type& get(const t_type& t) + { + return boost::get(t); + } + }; + + template<> + struct type_selector + { + template + static const std::type_info& get_type(const t_type& t) + { + return typeid(t); + } + template + static const t_return_type& get(const t_type& t) + { + return t; + } + }; + template bool get_first_service_attachment_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, currency::tx_service_attachment& res) { for (const auto& item : tx_items) { - if (item.type() == typeid(currency::tx_service_attachment)) + typedef type_selector::value> TS; + if (TS::get_type(item) == typeid(currency::tx_service_attachment)) { - const currency::tx_service_attachment& tsa = boost::get(item); + const currency::tx_service_attachment& tsa = TS::template get(item); if (tsa.service_id == id && tsa.instruction == instruction) { res = tsa; @@ -25,4 +65,5 @@ namespace bc_services } return false; } -} \ No newline at end of file + +} diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 8de65d46..17ed1fbd 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -3161,7 +3161,7 @@ bool blockchain_storage::get_pos_votes(uint64_t start_index, uint64_t end_index, summary[v.first].no++; } } - for (const auto s_entry : summary) + for (const auto& s_entry : summary) { r.votes.push_back(s_entry.second); r.votes.back().proposal_id = s_entry.first; @@ -3828,14 +3828,7 @@ bool blockchain_storage::unprocess_blockchain_tx_extra(const transaction& tx) if (ei.m_asset_operation.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED) { crypto::public_key asset_id = currency::null_pkey; - if (ei.m_asset_operation.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) - { - calculate_asset_id(ei.m_asset_operation.descriptor.owner, nullptr, &asset_id); - } - else - { - CHECK_AND_NO_ASSERT_MES(false, false, "asset operation not implemented"); - } + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ei.m_asset_operation, nullptr, &asset_id), false, "get_or_calculate_asset_id failed"); r = pop_asset_info(asset_id); CHECK_AND_ASSERT_MES(r, false, "failed to pop_alias_info"); } @@ -4086,15 +4079,14 @@ bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id) //------------------------------------------------------------------ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& avc) { -// asset_id = AUTO_VAL_INIT(asset_id); -// CHECK_AND_ASSERT_MES(validate_asset_operation_balance_proof(tx, tx_id, ado, asset_id), false, "asset operation validation failed!"); - CHECK_AND_ASSERT_MES(avc.ado.opt_proof.has_value(), false, "Ownership validation failed - missing signature"); - + asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop); + bool r = get_type_in_variant_container(avc.tx.proofs, aoop); + CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed - missing signature (asset_operation_ownership_proof)"); CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has invalid history size() == 0"); crypto::public_key owner_key = avc.asset_op_history->back().descriptor.owner; - return crypto::check_signature(get_signature_hash_for_asset_operation(avc.ado), owner_key, *avc.ado.opt_proof); + return crypto::verify_schnorr_sig(avc.tx_id, owner_key, aoop.gss); } //------------------------------------------------------------------ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) @@ -4105,12 +4097,13 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) { - calculate_asset_id(avc.ado.descriptor.owner, &avc.asset_id_pt, &avc.asset_id); + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); + avc.asset_op_history = m_db_assets.find(avc.asset_id); CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << avc.asset_id << " has already been registered"); avc.amount_to_validate = ado.descriptor.current_supply; - CHECK_AND_ASSERT_MES(validate_asset_operation_amount_proof(avc), false, "asset operation validation failed!"); + CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "asset operation validation failed!"); assets_container::t_value_type local_asset_history = AUTO_VAL_INIT(local_asset_history); local_asset_history.push_back(ado); @@ -4119,14 +4112,12 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has } else { - CHECK_AND_ASSERT_MES(avc.ado.opt_asset_id, false, "asset_id not provided for asset altering operation"); - avc.asset_op_history = m_db_assets.find(*avc.ado.opt_asset_id); - avc.asset_id = *avc.ado.opt_asset_id; // consider redisign - avc.asset_id_pt.from_public_key(avc.asset_id); + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); + avc.asset_op_history = m_db_assets.find(avc.asset_id); CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << avc.asset_id << " has not been registered"); // check ownership permission - if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE /*|| ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN*/) { bool r = validate_ado_ownership(avc); CHECK_AND_ASSERT_MES(r, false, "Faild to validate ownership of asset_descriptor_operation, rejecting"); @@ -4157,19 +4148,19 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has } else { - LOG_ERROR("Unknown operation type: " << ado.operation_type); + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); return false; } if (need_to_validate_balance_proof) { - bool r = validate_asset_operation_amount_proof(avc); + bool r = validate_asset_operation_amount_commitment(avc); CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation"); } assets_container::t_value_type local_asset_history = *avc.asset_op_history; local_asset_history.push_back(ado); - m_db_assets.set(*avc.ado.opt_asset_id, local_asset_history); + m_db_assets.set(avc.asset_id, local_asset_history); switch(ado.operation_type) { @@ -4183,7 +4174,7 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); break; default: - LOG_ERROR("Unknown operation type: " << ado.operation_type); + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); } } @@ -5816,7 +5807,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti }; //inputs - for (const auto in : tx.vin) + for (const auto& in : tx.vin) { if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(in)) return false; @@ -5830,7 +5821,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti return false; } //outputs - for (const auto out : tx.vout) + for (const auto& out : tx.vout) { if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(out)) return false; @@ -5846,7 +5837,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti size_t count_ado = 0; //extra - for (const auto el : tx.extra) + for (const auto& el : tx.extra) { if (el.type() == typeid(asset_descriptor_operation)) count_ado++; @@ -5861,7 +5852,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti } //attachments - for (const auto el : tx.attachment) + for (const auto& el : tx.attachment) { if (!var_is_after_hardfork_2_zone && !is_allowed_before_hardfork2(el)) return false; diff --git a/src/currency_core/checkpoints_create.h b/src/currency_core/checkpoints_create.h index 77907927..49d10037 100644 --- a/src/currency_core/checkpoints_create.h +++ b/src/currency_core/checkpoints_create.h @@ -27,7 +27,6 @@ namespace currency ADD_CHECKPOINT(1161000, "96990d851b484e30190678756ba2a4d3a2f92b987e2470728ac1e38b2bf35908"); ADD_CHECKPOINT(1480000, "5dd3381eec35e8b4eba4518bfd8eec682a4292761d92218fd59b9f0ffedad3fe"); ADD_CHECKPOINT(2000000, "7b6698a8cc279aa78d6263f01fef186bd16f5b1ea263a7f4714abc1d506b9cb3"); - ADD_CHECKPOINT(2390000, "10797d34349d0ef1d1ab4b41ada6f8f2c2f86a7f7eebe44dd2ba06067cb47e0a"); #endif return true; diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 8da2e671..b5aa7fab 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -438,18 +438,21 @@ namespace currency END_BOOST_SERIALIZATION() }; - // 1) for txs without ZC inputs: proves that balance point = lin(G) (cancels out G component of outputs' amount commitments, asset tags assumed to be H (native coin) and non-blinded) - // 2) for txs with ZC inputs: proves that balance point = lin(X) (cancels out X component of blinded asset tags within amount commitments for both outputs and inputs (pseudo outs)) + // First part of a double Schnorr proof: + // 1) for txs without ZC inputs: proves that balance point = lin(G) (cancels out G component of outputs' amount commitments, asset tags assumed to be H (native coin) and non-blinded) + // 2) for txs with ZC inputs: proves that balance point = lin(X) (cancels out X component of blinded asset tags within amount commitments for both outputs and inputs (pseudo outs)) + // Second part: + // proof of knowing transaction secret key (with respect to G) struct zc_balance_proof { - crypto::generic_schnorr_sig_s ss; + crypto::generic_double_schnorr_sig_s dss; BEGIN_SERIALIZE_OBJECT() - FIELD(ss) + FIELD(dss) END_SERIALIZE() BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(ss) + BOOST_SERIALIZE(dss) END_BOOST_SERIALIZATION() }; @@ -772,7 +775,6 @@ namespace currency uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; asset_descriptor_base descriptor; crypto::public_key amount_commitment; // premultiplied by 1/8 - boost::optional opt_proof; // operation proof - for update/emit boost::optional opt_asset_id; // target asset_id - for update/emit uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER; @@ -781,7 +783,6 @@ namespace currency FIELD(descriptor) FIELD(amount_commitment) END_VERSION_UNDER(1) - FIELD(opt_proof) FIELD(opt_asset_id) END_SERIALIZE() @@ -790,7 +791,6 @@ namespace currency BOOST_SERIALIZE(descriptor) BOOST_SERIALIZE(amount_commitment) BOOST_END_VERSION_UNDER(1) - BOOST_SERIALIZE(opt_proof) BOOST_SERIALIZE(opt_asset_id) END_BOOST_SERIALIZATION() }; @@ -816,6 +816,21 @@ namespace currency }; + struct asset_operation_ownership_proof + { + crypto::generic_schnorr_sig_s gss; + uint8_t version = 0; + + BEGIN_VERSIONED_SERIALIZE(0, version) + FIELD(gss) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(gss) + BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(version) + END_BOOST_SERIALIZATION() + }; struct extra_padding @@ -921,7 +936,7 @@ namespace currency typedef boost::variant signature_v; - typedef boost::variant proof_v; + typedef boost::variant proof_v; //include backward compatibility defintions @@ -1108,6 +1123,7 @@ BLOB_SERIALIZER(currency::txout_to_key); BOOST_CLASS_VERSION(currency::asset_descriptor_operation, 1); BOOST_CLASS_VERSION(currency::asset_operation_proof, 1); +BOOST_CLASS_VERSION(currency::asset_operation_ownership_proof, 1); // txin_v variant currency @@ -1178,6 +1194,7 @@ SET_VARIANT_TAGS(currency::zc_balance_proof, 48, "zc_balance_proof"); SET_VARIANT_TAGS(currency::asset_descriptor_operation, 49, "asset_descriptor_base"); SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof"); +SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation_ownership_proof"); diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 39b0a9e0..c1335126 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 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 @@ -10,7 +10,7 @@ #ifndef TESTNET #define CURRENCY_FORMATION_VERSION 84 #else -#define CURRENCY_FORMATION_VERSION 94 +#define CURRENCY_FORMATION_VERSION 97 #endif #define CURRENCY_GENESIS_NONCE (CURRENCY_FORMATION_VERSION + 101011010121) //bender's nightmare @@ -227,7 +227,7 @@ #define CURRENCY_POOLDATA_FOLDERNAME_PREFIX "poolstate_" #define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1" #define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX "blockchain_" -#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v1" +#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v2" #define P2P_NET_DATA_FILENAME "p2pstate.bin" #define MINER_CONFIG_FILENAME "miner_conf.json" @@ -250,8 +250,8 @@ #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" #ifndef TESTNET -#define WALLET_FILE_SERIALIZATION_VERSION 161 -#define WALLET_FILE_LAST_SUPPORTED_VERSION 161 +#define WALLET_FILE_SERIALIZATION_VERSION 162 +#define WALLET_FILE_LAST_SUPPORTED_VERSION 162 #else #define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+76) #define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+76) @@ -264,10 +264,10 @@ #define BLOCK_MINOR_VERSION_GENESIS 0 #define BLOCK_MAJOR_VERSION_INITIAL 0 #ifndef TESTNET -#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624 -#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999 -#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 -#define ZANO_HARDFORK_04_AFTER_HEIGHT 999999999 +#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624 // 2019-09-21 20:25:16 +#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999 // 2021-04-05 09:11:45 +#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 // 2021-06-01 23:28:10 +#define ZANO_HARDFORK_04_AFTER_HEIGHT 2555000 // 2024-03-21 10:16:46 (expected) #else /////// Zarcanum Testnet ////////////////////////////// #define ZANO_HARDFORK_01_AFTER_HEIGHT 0 diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 112ad3ad..876c2d17 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -76,7 +76,10 @@ namespace currency bool core::handle_command_line(const boost::program_options::variables_map& vm) { m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir); - m_stop_after_height = static_cast(command_line::get_arg(vm, command_line::arg_stop_after_height)); + m_stop_after_height = 0; + if(command_line::has_arg(vm, command_line::arg_stop_after_height)) + m_stop_after_height = static_cast(command_line::get_arg(vm, command_line::arg_stop_after_height)); + if (m_stop_after_height != 0) { LOG_PRINT_YELLOW("Daemon will STOP after block " << m_stop_after_height, LOG_LEVEL_0); diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 681850d9..1da81169 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -171,8 +171,8 @@ namespace currency asset_descriptor_operation ado{}; if (is_asset_emitting_transaction(tx, &ado)) { - crypto::point_t asset_id_pt = crypto::c_point_0; - calculate_asset_id(ado.descriptor.owner, &asset_id_pt, nullptr); // TODO @#@# optimization: this expensive calculation should be done only once + crypto::point_t asset_id_pt{}; + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &asset_id_pt, nullptr), false, "get_or_calculate_asset_id failed"); // TODO @#@# expensive operation, consider caching pseudo_outs_blinded_asset_ids.emplace_back(asset_id_pt); // additional ring member for asset emitting tx } @@ -301,8 +301,8 @@ namespace currency #ifndef NDEBUG CHECK_AND_ASSERT_MES(commitment_to_zero == secret_x * crypto::c_point_G, false, "internal error: commitment_to_zero is malformed (G)"); #endif - r = crypto::generate_schnorr_sig(tx_id, commitment_to_zero, secret_x, proof.ss); - CHECK_AND_ASSERT_MES(r, false, "generate_schnorr_sig (G) failed"); + r = crypto::generate_double_schnorr_sig(tx_id, commitment_to_zero, secret_x, ogc.tx_pub_key_p, ogc.tx_key.sec, proof.dss); + CHECK_AND_ASSERT_MES(r, false, "generate_double_schnorr_sig (G, G) failed"); } else // i.e. zc_inputs_count != 0 { @@ -326,8 +326,8 @@ namespace currency bool commitment_to_zero_is_sane = commitment_to_zero == secret_x * crypto::c_point_X; CHECK_AND_ASSERT_MES(commitment_to_zero_is_sane, false, "internal error: commitment_to_zero is malformed (X)"); #endif - r = crypto::generate_schnorr_sig(tx_id, commitment_to_zero, secret_x, proof.ss); - CHECK_AND_ASSERT_MES(r, false, "generate_schnorr_sig (X) failed"); + r = crypto::generate_double_schnorr_sig(tx_id, commitment_to_zero, secret_x, ogc.tx_pub_key_p, ogc.tx_key.sec, proof.dss); + CHECK_AND_ASSERT_MES(r, false, "genergenerate_double_schnorr_sigate_schnorr_sig (X, G) failed"); } return true; @@ -447,11 +447,9 @@ namespace currency tx = AUTO_VAL_INIT_T(transaction); tx.version = tx_version; - keypair txkey_local{}; - if (!tx_one_time_key_to_use) - txkey_local = keypair::generate(); - const keypair& txkey = tx_one_time_key_to_use ? *tx_one_time_key_to_use : txkey_local; - add_tx_pub_key_to_extra(tx, txkey.pub); + 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()); + add_tx_pub_key_to_extra(tx, tx_gen_context.tx_key.pub); if (extra_nonce.size()) if (!add_tx_extra_userdata(tx, extra_nonce)) return false; @@ -488,7 +486,6 @@ namespace currency } // fill outputs - tx_generation_context tx_gen_context{}; tx_gen_context.resize(zc_ins_count, destinations.size()); // auxiliary data for each output uint64_t output_index = 0; std::set deriv_cache; @@ -496,7 +493,7 @@ namespace currency { finalized_tx result = AUTO_VAL_INIT(result); uint8_t tx_outs_attr = 0; - r = construct_tx_out(d, txkey.sec, output_index, tx, deriv_cache, account_keys(), + r = construct_tx_out(d, tx_gen_context.tx_key.sec, output_index, tx, deriv_cache, account_keys(), tx_gen_context.asset_id_blinding_masks[output_index], tx_gen_context.amount_blinding_masks[output_index], tx_gen_context.blinded_asset_ids[output_index], tx_gen_context.amount_commitments[output_index], result, tx_outs_attr); CHECK_AND_ASSERT_MES(r, false, "construct_tx_out failed, output #" << output_index << ", amount: " << print_money_brief(d.amount)); @@ -576,7 +573,7 @@ namespace currency return true; } //----------------------------------------------------------------------------------------------- - bool validate_asset_operation_amount_proof(asset_op_verification_context& context)// const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado, crypto::public_key& asset_id) + bool validate_asset_operation_amount_commitment(asset_op_verification_context& context) { CHECK_AND_ASSERT_MES(count_type_in_variant_container(context.tx.proofs) == 1, false, "asset_operation_proof not present or present more than once"); const asset_operation_proof& aop = get_type_in_variant_container_by_ref(context.tx.proofs); @@ -608,6 +605,8 @@ namespace currency bool r = get_type_in_variant_container(tx.proofs, balance_proof); CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof is missing in tx proofs"); + crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + size_t zc_inputs_count = 0; uint64_t bare_inputs_sum = additional_inputs_amount_and_fees_for_mining_tx; for(auto& vin : tx.vin) @@ -645,7 +644,7 @@ namespace currency { if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) { - // opt_amount_commitment supposed to be validated earlier in validate_asset_operation() + // amount_commitment supposed to be validated earlier in validate_asset_operation_amount_commitment() sum_of_pseudo_out_amount_commitments += crypto::point_t(ado.amount_commitment); // *1/8 } else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) @@ -675,13 +674,13 @@ namespace currency CHECK_AND_ASSERT_MES(zc_inputs_count == zc_sigs_count, false, "zc inputs count (" << zc_inputs_count << ") and zc sigs count (" << zc_sigs_count << ") missmatch"); if (zc_inputs_count > 0) { - r = crypto::verify_schnorr_sig(tx_id, commitment_to_zero.to_public_key(), balance_proof.ss); - CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof (X) is invalid"); + r = crypto::verify_double_schnorr_sig(tx_id, commitment_to_zero, tx_pub_key, balance_proof.dss); + CHECK_AND_ASSERT_MES(r, false, "verify_double_schnorr_sig (X, G) is invalid"); } else { - r = crypto::verify_schnorr_sig(tx_id, commitment_to_zero.to_public_key(), balance_proof.ss); - CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof (G) is invalid"); + r = crypto::verify_double_schnorr_sig(tx_id, commitment_to_zero, tx_pub_key, balance_proof.dss); + CHECK_AND_ASSERT_MES(r, false, "verify_double_schnorr_sig (G, G) is invalid"); } return true; } @@ -1138,20 +1137,21 @@ namespace currency return origin_blob; } //--------------------------------------------------------------- - bool validate_ado_update_allowed(const asset_descriptor_base& a, const asset_descriptor_base& b) + bool validate_ado_update_allowed(const asset_descriptor_base& new_ado, const asset_descriptor_base& prev_ado) { - if (a.total_max_supply != b.total_max_supply) return false; - //if (a.current_supply != b.current_supply) return false; - if (a.decimal_point != b.decimal_point) return false; - if (a.ticker != b.ticker) return false; - if (a.full_name != b.full_name) return false; + if (new_ado.total_max_supply != prev_ado.total_max_supply) return false; + if (new_ado.current_supply > prev_ado.total_max_supply) return false; + if (new_ado.decimal_point != prev_ado.decimal_point) return false; + if (new_ado.ticker != prev_ado.ticker) return false; + if (new_ado.full_name != prev_ado.full_name) return false; //a.meta_info; - if (a.owner != b.owner) return false; - if (a.hidden_supply != b.hidden_supply) return false; + //if (a.owner != b.owner) return false; + if (new_ado.hidden_supply != prev_ado.hidden_supply) return false; return true; } //--------------------------------------------------------------- + /* crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado) { asset_descriptor_operation ado_local = ado; @@ -1165,6 +1165,7 @@ namespace currency { op.opt_proof = boost::none; } + */ //--------------------------------------------------------------- bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, const account_keys& self, uint8_t tx_outs_attr /* = CURRENCY_TO_KEY_OUT_RELAXED */) @@ -2111,20 +2112,45 @@ namespace currency } #define CRYPTO_HASH_ASSET_ID_ITERATIONS 1024 - void calculate_asset_id(const crypto::public_key& asset_owner, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key) + bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key) { - crypto::hash h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, asset_owner); + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || + ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || + ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN ) + { + CHECK_AND_ASSERT_MES(ado.opt_asset_id.has_value(), false, "ado.opt_asset_id has no value, op: " << (int)ado.operation_type << ", " << get_asset_operation_type_string(ado.operation_type)); + //LOG_PRINT_YELLOW("ado.opt_asset_id = " << ado.opt_asset_id.get(), LOG_LEVEL_0); + if (p_result_pub_key) + *p_result_pub_key = ado.opt_asset_id.get(); + if (p_result_point) + *p_result_point = crypto::point_t(ado.opt_asset_id.get()); + return true; + } + + // otherwise, calculate asset id + + crypto::hash_helper_t::hs_t hsc; + hsc.add_32_chars(CRYPTO_HDS_ASSET_ID); + hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.ticker)); + hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.full_name)); + hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.meta_info)); + hsc.add_scalar(crypto::scalar_t(ado.descriptor.total_max_supply)); + hsc.add_scalar(crypto::scalar_t(ado.descriptor.decimal_point)); + hsc.add_pub_key(ado.descriptor.owner); + crypto::hash h = hsc.calc_hash_no_reduce(); // this hash function needs to be computationally expensive (s.a. the whitepaper) for(uint64_t i = 0; i < CRYPTO_HASH_ASSET_ID_ITERATIONS; ++i) h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, h, i); - crypto::point_t local_point{}; - if (!p_result_point) - p_result_point = &local_point; - *p_result_point = crypto::hash_helper_t::hp(&h, sizeof h); + crypto::point_t result = crypto::hash_helper_t::hp(&h, sizeof h); + if (p_result_point) + *p_result_point = result; if (p_result_pub_key) - p_result_point->to_public_key(*p_result_pub_key); + result.to_public_key(*p_result_pub_key); + + //LOG_PRINT_YELLOW("calculated asset_id = " << result, LOG_LEVEL_0); + return true; } const asset_descriptor_base& get_native_coin_asset_descriptor() @@ -2155,14 +2181,20 @@ namespace currency { if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) { - crypto::secret_key asset_control_key{}; - bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY); - CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed"); + //crypto::secret_key asset_control_key{}; + //bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY); + //CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed"); + // + // old: + // asset_control_key = Hs(CRYPTO_HDS_ASSET_CONTROL_KEY, 8 * tx_key.sec * sender_account_keys.account_address.spend_public_key, 0) + // ado.descriptor.owner = asset_control_key * G + + ado.descriptor.owner = sender_account_keys.account_address.spend_public_key; - calculate_asset_id(ado.descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id); + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed"); // calculate amount blinding mask - gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, asset_control_key, tx_key.pub); + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec); // set correct asset_id to the corresponding destination entries uint64_t amount_of_emitted_asset = 0; @@ -2179,16 +2211,47 @@ namespace currency gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed"); + + // calculate amount blinding mask + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec); + gen_context.ao_commitment_in_outputs = true; + + // set correct asset_id to the corresponding destination entries + uint64_t amount_of_burned_assets = 0; + for (auto& item : ftp.sources) + { + if (item.asset_id == gen_context.ao_asset_id) + { + amount_of_burned_assets += item.amount; + } + } + for (auto& item : ftp.prepared_destinations) + { + if (item.asset_id == gen_context.ao_asset_id) + { + CHECK_AND_ASSERT_THROW_MES(amount_of_burned_assets >= item.amount, "Failed to find burn amount, failed condition: amount_of_burned_assets(" << amount_of_burned_assets << ") >= item.amount(" << item.amount << ")"); + amount_of_burned_assets -= item.amount; + } + } + ado.descriptor.current_supply -= amount_of_burned_assets; + + gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; + ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + + if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_burn{ &ado }); + + } else { if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) { - CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT"); + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed"); - gen_context.ao_asset_id = *ado.opt_asset_id; - gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id); // calculate amount blinding mask - gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key, tx_key.pub); + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec); // set correct asset_id to the corresponding destination entries uint64_t amount_of_emitted_asset = 0; @@ -2213,47 +2276,27 @@ namespace currency //fields that not supposed to be changed? } - else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) - { - CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN"); - - gen_context.ao_asset_id = *ado.opt_asset_id; - gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id); - // calculate amount blinding mask - gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key, tx_key.pub); - gen_context.ao_commitment_in_outputs = true; - - // set correct asset_id to the corresponding destination entries - uint64_t amount_of_burned_assets = 0; - for (auto& item: ftp.sources) - { - if (item.asset_id == gen_context.ao_asset_id) - { - amount_of_burned_assets += item.amount; - } - } - for (auto& item : ftp.prepared_destinations) - { - if (item.asset_id == gen_context.ao_asset_id ) - { - CHECK_AND_ASSERT_THROW_MES(amount_of_burned_assets >= item.amount, "Failed to find burn amount, failed condition: amount_of_burned_assets(" << amount_of_burned_assets << ") >= item.amount("<< item.amount << ")"); - amount_of_burned_assets -= item.amount; - } - } - ado.descriptor.current_supply -= amount_of_burned_assets; - - gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; - ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); - } - if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_seal{ &ado }); + ftp.need_to_generate_ado_proof = true; + /* //seal it with owners signature crypto::signature sig = currency::null_sig; - crypto::public_key pub_k = currency::null_pkey; - crypto::secret_key_to_public_key(ftp.asset_control_key, pub_k); - crypto::generate_signature(get_signature_hash_for_asset_operation(ado), pub_k, ftp.asset_control_key, sig); + crypto::hash h = get_signature_hash_for_asset_operation(ado); + if (ftp.pthirdparty_sign_handler) + { + bool r = ftp.pthirdparty_sign_handler->sign(h, ftp.ado_current_asset_owner, sig); + CHECK_AND_ASSERT_MES(r, false, "asset thirparty sign failed"); + } + else + { + crypto::public_key pub_k = currency::null_pkey; + crypto::secret_key_to_public_key(sender_account_keys.spend_secret_key, pub_k); + CHECK_AND_ASSERT_MES(ftp.ado_current_asset_owner == pub_k, false, "asset owner key not matched with provided private key for asset operation signing"); + crypto::generate_signature(h, pub_k, account_keys.spend_secret_key, sig); + } ado.opt_proof = sig; + */ } return true; } @@ -2438,15 +2481,14 @@ namespace currency LOG_PRINT_YELLOW("WARNING: tx v1 should not use ZC inputs", LOG_LEVEL_0); } + tx_generation_context& gen_context = result.ftp.gen_context; - - keypair txkey = AUTO_VAL_INIT(txkey); if (!append_mode) { - txkey = keypair::generate(); + gen_context.set_tx_key(keypair::generate()); //deterministic_generate_tx_onetime_key(key_images_total, sender_account_keys, txkey); - add_tx_pub_key_to_extra(tx, txkey.pub); - one_time_tx_secret_key = txkey.sec; + add_tx_pub_key_to_extra(tx, gen_context.tx_key.pub); + one_time_tx_secret_key = gen_context.tx_key.sec; //add flags etc_tx_flags16_t e = AUTO_VAL_INIT(e); @@ -2455,13 +2497,12 @@ namespace currency //include offers if need tx.attachment = attachments; - encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, txkey, result.derivation); + encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, gen_context.tx_key, result.derivation); } else { - txkey.pub = get_tx_pub_key_from_extra(tx); - txkey.sec = one_time_tx_secret_key; - CHECK_AND_ASSERT_MES(txkey.pub != null_pkey && txkey.sec != null_skey, false, "In append mode both public and secret keys must be provided"); + gen_context.set_tx_key(keypair{get_tx_pub_key_from_extra(tx), one_time_tx_secret_key}); + CHECK_AND_ASSERT_MES(gen_context.tx_key.pub != null_pkey && gen_context.tx_key.sec != null_skey, false, "In append mode both public and secret keys must be provided"); //separately encrypt attachments without putting extra result.derivation = get_encryption_key_derivation(true, tx, sender_account_keys); @@ -2471,7 +2512,7 @@ namespace currency std::vector extra_local = extra; std::vector attachments_local = attachments; - encrypt_attach_visitor v(was_attachment_crypted_entries, derivation, txkey, account_public_address(), sender_account_keys); + encrypt_attach_visitor v(was_attachment_crypted_entries, derivation, gen_context.tx_key, account_public_address(), sender_account_keys); for (auto& a : attachments_local) boost::apply_visitor(v, a); for (auto& a : extra_local) @@ -2481,7 +2522,7 @@ namespace currency tx.attachment.insert(tx.attachment.end(), attachments_local.begin(), attachments_local.end()); tx.extra.insert(tx.extra.end(), extra_local.begin(), extra_local.end()); - for (const auto in : tx.vin) + for (const auto& in : tx.vin) { if (in.type() == typeid(txin_zc_input)) { @@ -2499,8 +2540,6 @@ namespace currency // OUTs // std::vector shuffled_dsts(destinations); - //size_t outputs_to_be_constructed = shuffled_dsts.size(); - tx_generation_context& gen_context = result.ftp.gen_context; gen_context.resize(zc_inputs_count, tx.vout.size() + shuffled_dsts.size()); // ASSET oprations handling @@ -2510,7 +2549,7 @@ namespace currency pado = get_type_in_variant_container(tx.extra); if (pado) { - bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, txkey, shuffled_dsts); + bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, gen_context.tx_key, shuffled_dsts); CHECK_AND_ASSERT_MES(r, false, "Failed to construct_tx_handle_ado()"); if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation{ pado }); } @@ -2533,7 +2572,7 @@ namespace currency if (!(flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) && all_inputs_are_obviously_native_coins && gen_context.ao_asset_id == currency::null_pkey) dst_entr.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // all inputs are obviously native coins -- all outputs must have explicit asset ids (unless there's an asset emission) - r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys, + r = construct_tx_out(dst_entr, gen_context.tx_key.sec, output_index, tx, deriv_cache, sender_account_keys, gen_context.asset_id_blinding_masks[output_index], gen_context.amount_blinding_masks[output_index], gen_context.blinded_asset_ids[output_index], gen_context.amount_commitments[output_index], result, tx_outs_attr); CHECK_AND_ASSERT_MES(r, false, "Failed to construct tx out"); @@ -2642,7 +2681,7 @@ namespace currency else { // NLSAG - r = generate_NLSAG_sig(tx_hash_for_signature, tx_prefix_hash, i_ + input_starter_index, source_entry, sender_account_keys, in_contexts[i_mapped], txkey, flags, tx, &ss_ring_s); + r = generate_NLSAG_sig(tx_hash_for_signature, tx_prefix_hash, i_ + input_starter_index, source_entry, sender_account_keys, in_contexts[i_mapped], gen_context.tx_key, flags, tx, &ss_ring_s); CHECK_AND_ASSERT_MES(r, false, "generate_NLSAG_sig failed"); } @@ -2684,6 +2723,25 @@ namespace currency aop.opt_amount_commitment_g_proof = aop_g_sig; tx.proofs.emplace_back(std::move(aop)); } + if(ftp.need_to_generate_ado_proof) + { + asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop); + + if (ftp.pthirdparty_sign_handler) + { + //ask third party to generate proof + r = ftp.pthirdparty_sign_handler->sign(tx_prefix_hash, ftp.ado_current_asset_owner, aoop.gss); + CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado by thirdparty"); + } + else + { + //generate signature by wallet account + r = crypto::generate_schnorr_sig(tx_prefix_hash, ftp.ado_current_asset_owner, sender_account_keys.spend_secret_key, aoop.gss); + CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado proof"); + } + if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_after_asset_ownership_proof_generated{ &aoop }); + tx.proofs.emplace_back(aoop); + } } //size_t prefix_size = get_object_blobsize(static_cast(tx)); @@ -3180,7 +3238,7 @@ namespace currency if (P_prime.to_public_key() != zo.stealth_address) return false; - crypto::point_t Q_prime = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * 8 * crypto::point_t(addr.view_public_key); // Q' * 8 =? Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V + crypto::point_t Q_prime = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(addr.view_public_key).modify_mul8(); // Q' * 8 =? Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V if (Q_prime != crypto::point_t(zo.concealing_point).modify_mul8()) return false; @@ -3319,7 +3377,7 @@ namespace currency return true; } //--------------------------------------------------------------- - bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id) + bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id, bool is_in_hardfork4) { if (!is_payment_id_size_ok(payment_id)) return false; @@ -3327,6 +3385,10 @@ namespace currency tx_service_attachment tsa = AUTO_VAL_INIT(tsa); tsa.service_id = BC_PAYMENT_ID_SERVICE_ID; tsa.body = payment_id; + if (is_in_hardfork4) + { + tsa.flags = TX_SERVICE_ATTACHMENT_ENCRYPT_BODY; + } att.push_back(tsa); return true; } diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index bd743c33..8f858303 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -134,15 +134,18 @@ namespace currency END_KV_SERIALIZE_MAP() }; - struct htlc_info - { - bool hltc_our_out_is_before_expiration; - }; + struct htlc_info + { + bool hltc_our_out_is_before_expiration; + }; + struct thirdparty_sign_handler + { + virtual bool sign(const crypto::hash& h, const crypto::public_key& owner_public_key, crypto::generic_schnorr_sig& sig); + }; struct finalize_tx_param { - uint64_t unlock_time; std::vector extra; std::vector attachments; @@ -158,10 +161,15 @@ namespace currency crypto::public_key spend_pub_key; // only for validations uint64_t tx_version; uint64_t mode_separate_fee = 0; - crypto::secret_key asset_control_key = currency::null_skey; + epee::misc_utils::events_dispatcher* pevents_dispatcher; - tx_generation_context gen_context{}; // solely for consolidated txs + + //crypto::secret_key asset_control_key = currency::null_skey; + crypto::public_key ado_current_asset_owner = null_pkey; + thirdparty_sign_handler* pthirdparty_sign_handler = nullptr; + mutable bool need_to_generate_ado_proof = false; + BEGIN_SERIALIZE_OBJECT() FIELD(unlock_time) @@ -179,9 +187,12 @@ namespace currency FIELD(spend_pub_key) FIELD(tx_version) FIELD(mode_separate_fee) - FIELD(asset_control_key) if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) + { FIELD(gen_context); + } + FIELD(ado_current_asset_owner) + FIELD(need_to_generate_ado_proof) END_SERIALIZE() }; @@ -264,7 +275,7 @@ namespace currency const std::vector& vouts, zc_outs_range_proof& result); bool check_tx_bare_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0); bool check_tx_balance(const transaction& tx, const crypto::hash& tx_id, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0); - bool validate_asset_operation_amount_proof(asset_op_verification_context& context); + bool validate_asset_operation_amount_commitment(asset_op_verification_context& context); const char* get_asset_operation_type_string(size_t asset_operation_type, bool short_name = false); //--------------------------------------------------------------- bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, @@ -331,7 +342,7 @@ namespace currency 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); - void calculate_asset_id(const crypto::public_key& asset_owner, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key); + bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key); const asset_descriptor_base& get_native_coin_asset_descriptor(); bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed = nullptr); @@ -420,7 +431,7 @@ namespace currency bool addendum_to_hexstr(const std::vector& add, std::string& hex_buff); bool hexstr_to_addendum(const std::string& hex_buff, std::vector& add); - bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id); + bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id, bool is_in_hardfork4 = false); bool add_padding_to_tx(transaction& tx, size_t count); bool is_service_tx(const transaction& tx); bool does_tx_have_only_mixin_inputs(const transaction& tx); @@ -661,7 +672,7 @@ namespace currency } //--------------------------------------------------------------- template - bool get_payment_id_from_tx(const t_container& att, std::string& payment_id) + bool get_payment_id_from_decrypted_container(const t_container& att, std::string& payment_id) { tx_service_attachment sa = AUTO_VAL_INIT(sa); if (bc_services::get_first_service_attachment_by_id(att, BC_PAYMENT_ID_SERVICE_ID, "", sa)) diff --git a/src/currency_core/currency_format_utils_transactions.cpp b/src/currency_core/currency_format_utils_transactions.cpp index 029eca38..291010a6 100644 --- a/src/currency_core/currency_format_utils_transactions.cpp +++ b/src/currency_core/currency_format_utils_transactions.cpp @@ -398,7 +398,7 @@ namespace currency CATCH_ENTRY2(std::vector{}); } //--------------------------------------------------------------- - bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key) + bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context) { //TODO: Implement this function before mainnet #ifdef TESTNET diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index 2fc8beaf..aeaa551a 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -243,6 +243,12 @@ namespace currency amount_blinding_masks.size() == outs_count; } + void set_tx_key(const keypair& kp) + { + tx_key = kp; + tx_pub_key_p = crypto::point_t(tx_key.pub); + } + // per output data std::vector asset_ids; std::vector blinded_asset_ids; // generate_zc_outs_range_proof @@ -274,6 +280,10 @@ namespace currency crypto::scalar_t ao_amount_blinding_mask {}; // generate_tx_balance_proof generate_ZC_sig bool ao_commitment_in_outputs = false; + // per tx data + keypair tx_key {}; // + crypto::point_t tx_pub_key_p = crypto::c_point_0; // == tx_key.pub + // consider redesign, some data may possibly be excluded from kv serialization -- sowle BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_ids) @@ -297,6 +307,8 @@ namespace currency KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_commitment) KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_blinding_mask) KV_SERIALIZE_POD_AS_HEX_STRING(ao_commitment_in_outputs) + KV_SERIALIZE_POD_AS_HEX_STRING(tx_key) + KV_SERIALIZE_POD_AS_HEX_STRING(tx_pub_key_p) END_KV_SERIALIZE_MAP() // solely for consolidated txs, asset opration fields are not serialized @@ -325,10 +337,14 @@ namespace currency //ao_amount_commitment //ao_amount_blinding_mask //ao_commitment_in_outputs + + FIELD(tx_key.pub) // TODO: change to sane serialization FIELD(tx_key) + FIELD(tx_key.sec) + FIELD(tx_pub_key_p) END_SERIALIZE() }; // struct tx_generation_context - bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key); + bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context); std::string transform_tx_to_str(const transaction& tx); transaction transform_str_to_tx(const std::string& tx_str); diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index d9ea6f6c..cb09bdb2 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -162,6 +162,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, command_line::arg_no_predownload); command_line::add_arg(desc_cmd_sett, command_line::arg_force_predownload); + command_line::add_arg(desc_cmd_sett, command_line::arg_process_predownload_from_path); command_line::add_arg(desc_cmd_sett, command_line::arg_validate_predownload); command_line::add_arg(desc_cmd_sett, command_line::arg_predownload_link); command_line::add_arg(desc_cmd_sett, command_line::arg_disable_ntp); diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 18cb69f3..f040b100 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 18cb69f348bae38186f3a8da8bc9fc9991d38cd1 +Subproject commit f040b10090a0246ee5f68a37bb4fcc13e6abebcc diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 6178141c..f1460e35 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -118,10 +118,9 @@ namespace currency res.minimum_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_pool_min_fee; auto & hf = m_core.get_blockchain_storage().get_core_runtime_config().hard_forks.m_height_the_hardfork_n_active_after; - res.is_hardfok_active.resize(hf.size()); for (size_t i = 0; i != hf.size(); i++) { - res.is_hardfok_active[i] = m_core.get_blockchain_storage().is_hardfork_active(i); + res.is_hardfok_active.push_back(m_core.get_blockchain_storage().is_hardfork_active(i)); } //conditional values @@ -680,7 +679,7 @@ namespace currency { std::list al_list; m_core.get_tx_pool().get_aliases_from_tx_pool(al_list); - for (const auto a : al_list) + for (const auto& a : al_list) { res.aliases_que.push_back(alias_info_to_rpc_alias_info(a)); } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 79a343de..27393a9a 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -793,7 +793,7 @@ namespace currency uint64_t minimum_fee; uint64_t last_block_timestamp; std::string last_block_hash; - std::vector is_hardfok_active; + std::list is_hardfok_active; //market uint64_t offers_count; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index f0dd80dd..1a1f1e8e 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1681,7 +1681,7 @@ bool simple_wallet::transfer(const std::vector &args_) std::vector attachments; - if (!payment_id.empty() && !set_payment_id_to_tx(attachments, payment_id)) + if (!payment_id.empty() && !set_payment_id_to_tx(attachments, payment_id, m_wallet->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))) { fail_msg_writer() << "provided (or embedded) payment id can't be set: \"" << payment_id << "\""; return true; diff --git a/src/version.h.in b/src/version.h.in index 707b9258..93d71c55 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "0" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 253 +#define PROJECT_VERSION_BUILD_NO 265 #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/wallet2.cpp b/src/wallet/wallet2.cpp index d4b19270..d94b717a 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -400,30 +400,18 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op { do { + crypto::public_key asset_id{}; + if (ado.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED) + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(get_or_calculate_asset_id(ado, nullptr, &asset_id), "get_or_calculate_asset_id failed"); + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) { - crypto::public_key self_check = AUTO_VAL_INIT(self_check); - crypto::secret_key asset_control_key = AUTO_VAL_INIT(asset_control_key); - bool r = derive_key_pair_from_key_pair(ptc.tx_pub_key, m_account.get_keys().spend_secret_key, asset_control_key, self_check, CRYPTO_HDS_ASSET_CONTROL_KEY); - if (!r) - { - //not critical error, continue to work - LOG_ERROR("Failed to derive_key_pair_from_key_pair for asset_descriptor_operation in tx " << ptc.tx_hash()); + if (ado.descriptor.owner != m_account.get_public_address().spend_public_key) break; - } - if (self_check != ado.descriptor.owner) - { - //still not critical error - LOG_ERROR("Public key from asset_descriptor_operation(" << ado.descriptor.owner << ") not much with derived public key(" << self_check << "), for tx" << ptc.tx_hash()); - break; - } - crypto::public_key asset_id{}; - calculate_asset_id(ado.descriptor.owner, nullptr, &asset_id); WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_own_asset_descriptors.count(asset_id) == 0, "asset with asset_id " << asset_id << " has already been registered in the wallet as own asset"); wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id]; asset_context.asset_descriptor = ado.descriptor; - asset_context.control_key = asset_control_key; std::stringstream ss; ss << "New Asset Registered:" @@ -440,22 +428,78 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op if (m_wcallback) m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); } - else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) { - WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ado.opt_asset_id, get_asset_operation_type_string(ado.operation_type) << " failed with empty opt_asset_id"); - auto it = m_own_asset_descriptors.find(*ado.opt_asset_id); - WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(it != m_own_asset_descriptors.end(), "asset with asset_id " << *ado.opt_asset_id << " not found during " << get_asset_operation_type_string(ado.operation_type)); - if (it->second.asset_descriptor.owner != ado.descriptor.owner) + auto it = m_own_asset_descriptors.find(asset_id); + if (it == m_own_asset_descriptors.end()) + break; + //asset had been updated + add_rollback_event(ptc.height, asset_update_event{ it->first, it->second }); + it->second.asset_descriptor = ado.descriptor; + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE ) + { + auto it = m_own_asset_descriptors.find(asset_id); + if (it == m_own_asset_descriptors.end()) { - //ownership of the asset had been transfered - add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second }); - m_own_asset_descriptors.erase(it); + if (ado.descriptor.owner == m_account.get_public_address().spend_public_key) + { + // ownership of the asset acquired + + wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id]; + asset_context.asset_descriptor = ado.descriptor; + + std::stringstream ss; + ss << "Asset ownership acquired:" + << ENDL << "asset id: " << asset_id + << ENDL << "Name: " << ado.descriptor.full_name + << ENDL << "Ticker: " << ado.descriptor.ticker + << ENDL << "Total Max Supply: " << print_asset_money(ado.descriptor.total_max_supply, ado.descriptor.decimal_point) + << ENDL << "Current Supply: " << print_asset_money(ado.descriptor.current_supply, ado.descriptor.decimal_point) + << ENDL << "Decimal Point: " << ado.descriptor.decimal_point; + + + add_rollback_event(ptc.height, asset_register_event{ asset_id }); + WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0); + if (m_wcallback) + m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); + } + else + { + // update event of the asset that we not control, skip + break; + } } else { - //asset had been updated - add_rollback_event(ptc.height, asset_update_event{ it->first, it->second }); - it->second.asset_descriptor = ado.descriptor; + //update event for asset that we control, check if ownership is still ours + if (ado.descriptor.owner != m_account.get_public_address().spend_public_key && !it->second.thirdparty_custody) + { + //ownership of the asset had been transfered + add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second }); + m_own_asset_descriptors.erase(it); + + std::stringstream ss; + ss << "Asset ownership lost:" + << ENDL << "asset id: " << asset_id + << ENDL << "New owner: " << ado.descriptor.owner + << ENDL << "Name: " << ado.descriptor.full_name + << ENDL << "Ticker: " << ado.descriptor.ticker + << ENDL << "Total Max Supply: " << print_asset_money(ado.descriptor.total_max_supply, ado.descriptor.decimal_point) + << ENDL << "Current Supply: " << print_asset_money(ado.descriptor.current_supply, ado.descriptor.decimal_point) + << ENDL << "Decimal Point: " << ado.descriptor.decimal_point; + + add_rollback_event(ptc.height, asset_register_event{ asset_id }); + WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0); + if (m_wcallback) + m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); + } + else + { + //just an update of the asset + add_rollback_event(ptc.height, asset_update_event{ it->first, it->second }); + it->second.asset_descriptor = ado.descriptor; + } } } } while (false); @@ -544,7 +588,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t all values m_payments entry, use this strict policy is required to protect exchanges from being feeded with useless outputs */ - uint64_t max_out_unlock_time = 0; + ptc.max_out_unlock_time = 0; std::vector outs; //uint64_t sum_of_native_outs = 0; // TODO: @#@# correctly calculate tx_money_got_in_outs for post-HF4 @@ -640,21 +684,29 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t auto it = m_key_images.find(ki); if (it != m_key_images.end()) { - // Issue that has been discovered by Luke Parker (twitter: @kayabaNerve) - // An attacker can quickly issue transaction that use same outputs ephemeral keys + same tx key, as a result both - // transaction's outputs would have same key image, so the wallet should have smart approach to this situation, ie - // use output that offer biggest output value.(tokens?) - + // We encountered an output with a key image already seen. This implies only one can be spent in the future (assuming the first isn't spent yet). + // To address this, we disregard such outputs and log a warning. + // + // It was later revealed that auditable wallets could still be vulnerable: an attacker might quickly broadcast a transaction + // using the same output's ephemeral keys + the same tx pub key. If the malicious transaction (potentially for a lesser amount) + // arrives first, the recipient would be unable to spend the funds from the second, real transaction. + // This attack vector was highlighted by Luke Parker (twitter: @kayabaNerve), who suggested selecting the output with the largest amount. + // Sadly, this fix only applies to classic RingCT transactions and is incompatible with our use of Confidential Assets. + // Consequently, we adopted a solution suggested by @crypto_zoidberg: verifying in zero knowledge that the sender possesses the transaction's + // secret key. This verification is integrated with the balance proof (double Schnorr proof). + // + // However, we continue to omit outputs with duplicate key images since they could originate from the same source (albeit impractically). + // -- sowle WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "m_key_images entry has wrong m_transfers index, it->second: " << it->second << ", m_transfers.size(): " << m_transfers.size()); const transfer_details& local_td = m_transfers[it->second]; - - std::stringstream ss; - ss << "tx " << ptc.tx_hash() << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" << - local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height << - ". This output can't ever be spent and will be skipped."; + ss << "tx " << ptc.tx_hash() << " @ block " << height << " has output #" << o << " with amount " << out.amount; + if (!out.is_native_coin()) + ss << "(asset_id: " << out.asset_id << ") "; + ss << "and key image " << ki << " that has already been seen in output #" << local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) + << " @ block " << local_td.m_spent_height << ". This output can't ever be spent and will be skipped."; WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0); if (m_wcallback) m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); @@ -671,9 +723,12 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t out_get_mixin_attr(out_v) != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) { std::stringstream ss; - ss << "output #" << o << " from tx " << ptc.tx_hash() << " with amount " << print_money_brief(outs[i_in_outs].amount) + ss << "output #" << o << " from tx " << ptc.tx_hash(); + if (!out.is_native_coin()) + ss << " asset_id: " << out.asset_id; + ss << " with amount " << print_money_brief(out.amount) << " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)out_get_mixin_attr(out_v) << ". Output is IGNORED."; - WLT_LOG_RED(ss.str(), LOG_LEVEL_0); + WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0); if (m_wcallback) m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str()); //if (out.is_native_coin()) @@ -777,8 +832,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t m_amount_gindex_to_transfer_id[amount_gindex_pair] = transfer_index; } - if (max_out_unlock_time < get_tx_unlock_time(tx, o)) - max_out_unlock_time = get_tx_unlock_time(tx, o); + if (ptc.max_out_unlock_time < get_tx_unlock_time(tx, o)) + ptc.max_out_unlock_time = get_tx_unlock_time(tx, o); if (out_type_to_key || out_type_zc) { @@ -832,40 +887,12 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } } - std::string payment_id; - if (has_in_transfers && get_payment_id_from_tx(tx.attachment, payment_id) && payment_id.size()) - { - payment_details payment; - payment.m_tx_hash = ptc.tx_hash(); - payment.m_amount = 0; - payment.m_block_height = height; - payment.m_unlock_time = max_out_unlock_time; - - for (const auto& bce : ptc.total_balance_change) - { - if (bce.second > 0) - { - if (bce.first == currency::native_coin_asset_id) - { - payment.m_amount = static_cast(bce.second); - }else - { - payment.subtransfers.push_back(payment_details_subtransfer{ bce.first, static_cast(bce.second)}); - } - } - } - m_payments.emplace(payment_id, payment); - WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount) << "subtransfers = " << payment.subtransfers.size()); - } - - if (ptc.spent_own_native_inputs) + //check if there are asset_registration that belong to this wallet + const asset_descriptor_operation* pado = get_type_in_variant_container(tx.extra); + if (pado && (ptc.employed_entries.receive.size() || ptc.employed_entries.spent.size() || pado->descriptor.owner == m_account.get_public_address().spend_public_key)) { //check if there are asset_registration that belong to this wallet - asset_descriptor_operation ado = AUTO_VAL_INIT(ado); - if (get_type_in_variant_container(tx.extra, ado)) - { - process_ado_in_new_transaction(ado, ptc); - } + process_ado_in_new_transaction(*pado, ptc); } if (has_in_transfers || has_out_transfers || is_derivation_used_to_encrypt(tx, derivation) || ptc.employed_entries.spent.size()) @@ -917,7 +944,7 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i { LOG_ERROR("wti.payment_id is expected to be empty. Go ahead."); } - get_payment_id_from_tx(decrypted_att, wti.payment_id); + get_payment_id_from_decrypted_container(decrypted_att, wti.payment_id); for (const auto& item : decrypted_att) { @@ -1261,7 +1288,7 @@ bool wallet2::handle_proposal(wallet_public::wallet_transfer_info& wti, const bc ed.is_a = cpd.a_addr.spend_public_key == m_account.get_keys().account_address.spend_public_key; change_contract_state(ed, wallet_public::escrow_contract_details_basic::proposal_sent, ms_id, wti); ed.private_detailes = cpd; - currency::get_payment_id_from_tx(decrypted_items, ed.payment_id); + currency::get_payment_id_from_decrypted_container(decrypted_items, ed.payment_id); ed.proposal = prop; ed.height = wti.height; wti.contract.resize(1); @@ -1530,8 +1557,42 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces } prepare_wti_decrypted_attachments(wti, decrypted_att); process_contract_info(wti, decrypted_att); + process_payment_id_for_wti(wti, tx_process_context); + } //---------------------------------------------------------------------------------------------------- +bool wallet2::process_payment_id_for_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& ptc) +{ + //if(this->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)) + { + if (wti.get_native_is_income() && wti.payment_id.size()) + { + payment_details payment; + payment.m_tx_hash = wti.tx_hash; + payment.m_amount = 0; + payment.m_block_height = wti.height; + payment.m_unlock_time = ptc.max_out_unlock_time; + + for (const auto& bce : ptc.total_balance_change) + { + if (bce.second > 0) + { + if (bce.first == currency::native_coin_asset_id) + { + payment.m_amount = static_cast(bce.second); + } + else + { + payment.subtransfers.push_back(payment_details_subtransfer{ bce.first, static_cast(bce.second) }); + } + } + } + m_payments.emplace(wti.payment_id, payment); + WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(wti.payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount) << "subtransfers = " << payment.subtransfers.size()); + } + } + return true; +} void wallet2::rise_on_transfer2(const wallet_public::wallet_transfer_info& wti) { PROFILE_FUNC("wallet2::rise_on_transfer2"); @@ -1582,7 +1643,7 @@ void wallet2::load_wti_from_process_transaction_context(wallet_public::wallet_tr { wti.remote_addresses = tx_process_context.recipients; wti.remote_aliases = tx_process_context.remote_aliases; - for (const auto bce : tx_process_context.total_balance_change) + for (const auto& bce : tx_process_context.total_balance_change) { wallet_public::wallet_sub_transfer_info wsti = AUTO_VAL_INIT(wsti); wsti.asset_id = bce.first; @@ -3322,7 +3383,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a return total; } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::balance(crypto::public_key asset_id, uint64_t& unlocked) const +uint64_t wallet2::balance(const crypto::public_key& asset_id, uint64_t& unlocked) const { std::unordered_map balances; uint64_t dummy; @@ -3336,6 +3397,12 @@ uint64_t wallet2::balance(crypto::public_key asset_id, uint64_t& unlocked) const return it->second.total; } //---------------------------------------------------------------------------------------------------- +uint64_t wallet2::balance(const crypto::public_key& asset_id) const +{ + uint64_t dummy = 0; + return balance(asset_id, dummy); +} +//---------------------------------------------------------------------------------------------------- bool wallet2::balance(std::unordered_map& balances, uint64_t& mined) const { mined = 0; @@ -3804,7 +3871,7 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans throw; } - add_sent_tx_detailed_info(tx, ft.ftp.prepared_destinations, ft.ftp.selected_transfers); + add_sent_tx_detailed_info(tx, ft.ftp.attachments, ft.ftp.prepared_destinations, ft.ftp.selected_transfers); m_tx_keys.insert(std::make_pair(tx_hash, ft.one_time_key)); if (m_watch_only) @@ -4847,7 +4914,7 @@ void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info currency::asset_descriptor_operation ado = AUTO_VAL_INIT(ado); bool r = get_type_in_variant_container(result_tx.extra, ado); CHECK_AND_ASSERT_THROW_MES(r, "Failed find asset info in tx"); - calculate_asset_id(ado.descriptor.owner, nullptr, &new_asset_id); + CHECK_AND_ASSERT_THROW_MES(get_or_calculate_asset_id(ado, nullptr, &new_asset_id), "get_or_calculate_asset_id failed"); m_custom_assets[new_asset_id] = ado.descriptor; } @@ -4871,7 +4938,8 @@ void wallet2::emmit_asset(const crypto::public_key asset_id, std::vectorsecond.control_key; + ctp.ado_current_asset_owner = rsp.asset_descriptor.owner; + //ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key; finalized_tx ft = AUTO_VAL_INIT(ft); this->transfer(ctp, ft, true, nullptr); @@ -4890,7 +4958,33 @@ void wallet2::update_asset(const crypto::public_key asset_id, const currency::as construct_tx_param ctp = get_default_construct_tx_param(); ctp.extra.push_back(asset_update_info); ctp.need_at_least_1_zc = true; - ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key; + currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb); + bool r = this->daemon_get_asset_info(asset_id, adb); + CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon"); + ctp.ado_current_asset_owner = adb.owner; + + finalized_tx ft = AUTO_VAL_INIT(ft); + this->transfer(ctp, ft, true, nullptr); + result_tx = ft.tx; +} +//---------------------------------------------------------------------------------------------------- +void wallet2::transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx) +{ + auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id); + CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list"); + + currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb); + bool r = this->daemon_get_asset_info(asset_id, adb); + CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon"); + + asset_descriptor_operation asset_update_info = AUTO_VAL_INIT(asset_update_info); + asset_update_info.descriptor = adb; + asset_update_info.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE; + asset_update_info.opt_asset_id = asset_id; + asset_update_info.descriptor.owner = new_owner; + construct_tx_param ctp = get_default_construct_tx_param(); + ctp.ado_current_asset_owner = adb.owner; + ctp.extra.push_back(asset_update_info); finalized_tx ft = AUTO_VAL_INIT(ft); this->transfer(ctp, ft, true, nullptr); @@ -4899,8 +4993,8 @@ void wallet2::update_asset(const crypto::public_key asset_id, const currency::as //---------------------------------------------------------------------------------------------------- void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx) { - auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id); - CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list"); + //auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id); + //CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list"); COMMAND_RPC_GET_ASSET_INFO::request req; req.asset_id = asset_id; COMMAND_RPC_GET_ASSET_INFO::response rsp; @@ -4923,7 +5017,7 @@ void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_b construct_tx_param ctp = get_default_construct_tx_param(); ctp.extra.push_back(asset_burn_info); ctp.need_at_least_1_zc = true; - ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key; + ctp.ado_current_asset_owner = rsp.asset_descriptor.owner; ctp.dsts.push_back(dst_to_burn); finalized_tx ft = AUTO_VAL_INIT(ft); @@ -5380,7 +5474,7 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details& send_transaction_to_network(tx); mark_transfers_as_spent(ftp.selected_transfers, std::string("escrow proposal sent, tx <") + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">, contract: " + epee::string_tools::pod_to_hex(ms_id)); - add_sent_tx_detailed_info(tx, ftp.prepared_destinations, ftp.selected_transfers); + add_sent_tx_detailed_info(tx, ftp.attachments, ftp.prepared_destinations, ftp.selected_transfers); print_tx_sent_message(tx, "(from multisig)", fee); } @@ -5548,7 +5642,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal proposal.tx_template = finalize_result.tx; wallet_public::ionic_swap_proposal_context ispc = AUTO_VAL_INIT(ispc); ispc.gen_context = finalize_result.ftp.gen_context; - ispc.one_time_skey = finalize_result.one_time_key; + //ispc.one_time_skey = finalize_result.one_time_key; std::string proposal_context_blob = t_serializable_object_to_blob(ispc); proposal.encrypted_context = crypto::chacha_crypt(static_cast(proposal_context_blob), finalize_result.derivation); return true; @@ -5586,7 +5680,7 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo r = t_unserializable_object_from_blob(ionic_context, decrypted_raw_context); THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to unserialize decrypted ionic_context"); - r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context, ionic_context.one_time_skey); + r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context); THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to validate decrypted ionic_context"); std::unordered_map amounts_provided_by_a; @@ -5754,7 +5848,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa construct_tx_param construct_param = get_default_construct_tx_param(); construct_param.fee = additional_fee; - crypto::secret_key one_time_key = ionic_context.one_time_skey; + crypto::secret_key one_time_key = ionic_context.gen_context.tx_key.sec; // TODO: figure out this mess with tx sec key -- sowle construct_param.crypt_address = m_account.get_public_address(); construct_param.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE; construct_param.mark_tx_as_complete = true; @@ -6250,12 +6344,12 @@ void wallet2::send_transaction_to_network(const transaction& tx) } //---------------------------------------------------------------------------------------------------------------- -void wallet2::add_sent_tx_detailed_info(const transaction& tx, +void wallet2::add_sent_tx_detailed_info(const transaction& tx, const std::vector& decrypted_att, const std::vector& destinations, const std::vector& selected_transfers) { payment_id_t payment_id; - get_payment_id_from_tx(tx.attachment, payment_id); + get_payment_id_from_decrypted_container(decrypted_att, payment_id); std::vector recipients; std::unordered_set used_addresses; @@ -6916,7 +7010,8 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx const currency::transaction& tx_for_mode_separate = msc.tx_for_mode_separate; assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts); - ftp.asset_control_key = ctp.asset_deploy_control_key; + ftp.ado_current_asset_owner = ctp.ado_current_asset_owner; + ftp.pthirdparty_sign_handler = ctp.pthirdparty_sign_handler; // // TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id // @@ -7057,7 +7152,7 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f //TIME_MEASURE_START(add_sent_tx_detailed_info_time); if (broadcast_tx) - add_sent_tx_detailed_info(result.tx, ftp.prepared_destinations, ftp.selected_transfers); + add_sent_tx_detailed_info(result.tx, ftp.attachments, ftp.prepared_destinations, ftp.selected_transfers); //TIME_MEASURE_FINISH(add_sent_tx_detailed_info_time); /* TODO @@ -7181,7 +7276,7 @@ void wallet2::check_and_throw_if_self_directed_tx_with_payment_id_requested(cons // it's self-directed tx payment_id_t pid; - bool has_payment_id = get_payment_id_from_tx(ctp.attachments, pid) && !pid.empty(); + bool has_payment_id = get_payment_id_from_decrypted_container(ctp.attachments, pid) && !pid.empty(); WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!has_payment_id, "sending funds to yourself with payment id is not allowed"); } //---------------------------------------------------------------------------------------------------- @@ -7331,8 +7426,9 @@ 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(); + 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); + set_payment_id_to_tx(ftp.attachments, payment_id, is_hf4); // put encrypted payer info into the extra ftp.crypt_address = destination_addr; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0caefca0..3097a9c5 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -323,6 +323,7 @@ namespace tools multisig_entries_map* pmultisig_entries = nullptr; crypto::public_key tx_pub_key = currency::null_pkey; uint64_t tx_expiration_ts_median = 0; + uint64_t max_out_unlock_time = 0; const crypto::hash& tx_hash() const { @@ -391,9 +392,10 @@ namespace tools void emmit_asset(const crypto::public_key asset_id, std::vector& destinations, currency::transaction& result_tx); void update_asset(const crypto::public_key asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx); void burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx); + void transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx); bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb); - + const std::unordered_map& get_own_assets() const { return m_own_asset_descriptors; } bool set_core_proxy(const std::shared_ptr& proxy); void set_pos_utxo_count_limits_for_defragmentation_tx(uint64_t min_outs, uint64_t max_outs); // don't create UTXO defrag. tx if there are less than 'min_outs' outs; don't put more than 'max_outs' outs void set_pos_decoys_count_for_defragmentation_tx(size_t decoys_count); @@ -404,7 +406,8 @@ namespace tools uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined, const crypto::public_key& asset_id = currency::native_coin_asset_id) const; bool balance(std::unordered_map& balances, uint64_t& mined) const; bool balance(std::list& balances, uint64_t& mined) const; - uint64_t balance(crypto::public_key asset_id, uint64_t& unloked) const; + uint64_t balance(const crypto::public_key& asset_id, uint64_t& unlocked) const; + uint64_t balance(const crypto::public_key& asset_id) const; uint64_t balance(uint64_t& unloked) const; @@ -688,6 +691,7 @@ namespace tools bool validate_sign(const std::string& buff, const crypto::signature& sig, const crypto::public_key& pkey); bool encrypt_buffer(const std::string& buff, std::string& res_buff); bool decrypt_buffer(const std::string& buff, std::string& res_buff); + bool is_in_hardfork_zone(uint64_t hardfork_index) const; construct_tx_param get_default_construct_tx_param(); @@ -739,6 +743,7 @@ private: void prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector& decrypted_att); void handle_money(const currency::block& b, const process_transaction_context& tx_process_context); void load_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); + bool process_payment_id_for_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context); void handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks); @@ -815,7 +820,8 @@ private: void load_keys2ki(bool create_if_not_exist, bool& need_to_resync); void send_transaction_to_network(const currency::transaction& tx); - void add_sent_tx_detailed_info(const currency::transaction& tx, + void add_sent_tx_detailed_info(const currency::transaction& tx, + const std::vector& decrypted_att, const std::vector& destinations, const std::vector& selected_indicies); void mark_transfers_as_spent(const std::vector& selected_transfers, const std::string& reason = std::string()); @@ -836,7 +842,6 @@ private: uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(uint64_t amount, const std::vector & key_offsets); uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_to_key& intk); uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_zc_input& inzc); - bool is_in_hardfork_zone(uint64_t hardfork_index) const; uint8_t out_get_mixin_attr(const currency::tx_out_v& out_t); const crypto::public_key& out_get_pub_key(const currency::tx_out_v& out_t, std::list& htlc_info_list); bool expand_selection_with_zc_input(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector& selected_indexes); diff --git a/src/wallet/wallet2_base.h b/src/wallet/wallet2_base.h index 52da0c59..d9c9589c 100644 --- a/src/wallet/wallet2_base.h +++ b/src/wallet/wallet2_base.h @@ -199,6 +199,7 @@ namespace tools END_SERIALIZE() }; + struct construct_tx_param { // preparing data for tx @@ -223,7 +224,9 @@ namespace tools bool shuffle = false; bool create_utxo_defragmentation_tx = false; bool need_at_least_1_zc = false; - crypto::secret_key asset_deploy_control_key = currency::null_skey; + //crypto::secret_key asset_deploy_control_key = currency::null_skey; + currency::thirdparty_sign_handler* pthirdparty_sign_handler = nullptr; + crypto::public_key ado_current_asset_owner = currency::null_pkey; }; struct mode_separate_context @@ -255,13 +258,11 @@ namespace tools struct wallet_own_asset_context { currency::asset_descriptor_base asset_descriptor; - crypto::secret_key control_key; - //uint64_t height = 0; + bool thirdparty_custody = false; BEGIN_BOOST_SERIALIZATION() BOOST_SERIALIZE(asset_descriptor) - BOOST_SERIALIZE(control_key) - //BOOST_SERIALIZE(height) + BOOST_SERIALIZE(thirdparty_custody) END_BOOST_SERIALIZATION() }; diff --git a/src/wallet/wallet_debug_events_definitions.h b/src/wallet/wallet_debug_events_definitions.h index c9845a9b..30d7885c 100644 --- a/src/wallet/wallet_debug_events_definitions.h +++ b/src/wallet/wallet_debug_events_definitions.h @@ -13,9 +13,20 @@ struct wde_construct_tx_handle_asset_descriptor_operation }; -//Wallet Debug Events struct wde_construct_tx_handle_asset_descriptor_operation_before_seal { currency::asset_descriptor_operation* pado; }; +struct wde_construct_tx_handle_asset_descriptor_operation_before_burn +{ + currency::asset_descriptor_operation* pado; +}; + + + +struct wde_construct_tx_after_asset_ownership_proof_generated +{ + currency::asset_operation_ownership_proof* pownership_proof; +}; + diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index 0b4b1970..6610bb7d 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -273,18 +273,28 @@ namespace wallet_public } }; - struct wallet_transfer_info_old : public wallet_transfer_info { - uint64_t amount = 0; - bool is_income = false; + //uint64_t amount = 0; + //bool is_income = false; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(is_income) - KV_SERIALIZE(amount) + KV_SERIALIZE_EPHEMERAL_N(uint64_t, wallet_transfer_info_to_amount, "amount") + KV_SERIALIZE_EPHEMERAL_N(bool, wallet_transfer_info_to_is_income, "is_income") + //KV_SERIALIZE(amount) KV_CHAIN_BASE(wallet_transfer_info) END_KV_SERIALIZE_MAP() + static uint64_t wallet_transfer_info_to_amount(const wallet_transfer_info_old& wtio) + { + return wtio.get_native_amount(); + } + + static bool wallet_transfer_info_to_is_income(const wallet_transfer_info_old& wtio) + { + return wtio.get_native_is_income(); + } + }; @@ -1226,6 +1236,29 @@ namespace wallet_public }; }; + struct COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY + { + typedef COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request request; + + struct response + { + std::list in; + std::list out; + //std::list pending; + //std::list failed; + std::list pool; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(in) + KV_SERIALIZE(out) + //KV_SERIALIZE(pending) + //KV_SERIALIZE(failed) + KV_SERIALIZE(pool) + END_KV_SERIALIZE_MAP() + }; + }; + + struct htlc_entry_info { currency::account_public_address counterparty_address; @@ -1407,12 +1440,10 @@ namespace wallet_public struct ionic_swap_proposal_context { currency::tx_generation_context gen_context; - crypto::secret_key one_time_skey; BEGIN_SERIALIZE_OBJECT() VERSION(0) //use VERSION_TO_MEMBER if it's more then 0 FIELD(gen_context) - FIELD(one_time_skey) END_SERIALIZE() }; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 498af626..a602ecba 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -276,6 +276,16 @@ namespace tools WALLET_RPC_CATCH_TRY_ENTRY(); } //------------------------------------------------------------------------------------------------------------------------------ + template + void copy_wallet_transfer_info_old_container(const t_from& from_c, t_to& to_c) + { + for (const auto& item : from_c) + { + to_c.push_back(wallet_public::wallet_transfer_info_old()); + *static_cast(&to_c.back()) = item; + } + } + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx) { //this is legacy api, should be removed after successful transition to HF4 @@ -286,20 +296,7 @@ namespace tools res.pi = rsp2.pi; res.total_transfers = rsp2.total_transfers; res.last_item_index = rsp2.last_item_index; - for (const auto& item : rsp2.transfers) - { - res.transfers.push_back(wallet_public::wallet_transfer_info_old()); - *static_cast(&res.transfers.back()) = item; - for (const auto& subitem : item.subtransfers) - { - if (subitem.asset_id == currency::native_coin_asset_id) - { - res.transfers.back().amount = subitem.amount; - res.transfers.back().is_income = subitem.is_income; - } - } - } - + copy_wallet_transfer_info_old_container(rsp2.transfers, res.transfers); return true; WALLET_RPC_CATCH_TRY_ENTRY(); } @@ -413,7 +410,7 @@ namespace tools std::vector& attachments = ctp.attachments; std::vector& extra = ctp.extra; - if (!payment_id.empty() && !currency::set_payment_id_to_tx(attachments, payment_id)) + if (!payment_id.empty() && !currency::set_payment_id_to_tx(attachments, payment_id, w.get_wallet()->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))) { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; er.message = std::string("payment id ") + payment_id + " is invalid and can't be set"; @@ -699,8 +696,19 @@ namespace tools return true; } + + bool wallet_rpc_server::on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::response& res, epee::json_rpc::error& er, connection_context& cntx) + { + wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response res_origin; + bool r = this->on_search_for_transactions2(req, res_origin, er, cntx); + copy_wallet_transfer_info_old_container(res_origin.in, res.in); + copy_wallet_transfer_info_old_container(res_origin.out, res.out); + copy_wallet_transfer_info_old_container(res_origin.pool, res.pool); + + return r; + } //------------------------------------------------------------------------------------------------------------------------------ - bool wallet_rpc_server::on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx) + bool wallet_rpc_server::on_search_for_transactions2(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx) { WALLET_RPC_BEGIN_TRY_ENTRY(); bool tx_id_specified = req.tx_id != currency::null_hash; @@ -753,6 +761,7 @@ namespace tools return true; WALLET_RPC_CATCH_TRY_ENTRY(); } + //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_get_mining_history(const wallet_public::COMMAND_RPC_GET_MINING_HISTORY::request& req, wallet_public::COMMAND_RPC_GET_MINING_HISTORY::response& res, epee::json_rpc::error& er, connection_context& cntx) { WALLET_RPC_BEGIN_TRY_ENTRY(); diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 989411eb..f95ae920 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -105,7 +105,8 @@ namespace tools MAP_JON_RPC_WE("sweep_below", on_sweep_below, wallet_public::COMMAND_SWEEP_BELOW) MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_public::COMMAND_SIGN_TRANSFER) MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_public::COMMAND_SUBMIT_TRANSFER) - MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS) + MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY) + MAP_JON_RPC_WE("search_for_transactions2", on_search_for_transactions2, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS) MAP_JON_RPC_WE("get_restore_info", on_getwallet_restore_info, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO) MAP_JON_RPC_WE("get_seed_phrase_info", on_get_seed_phrase_info, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO) MAP_JON_RPC_WE("get_mining_history", on_get_mining_history, wallet_public::COMMAND_RPC_GET_MINING_HISTORY) @@ -161,7 +162,8 @@ namespace tools bool on_sweep_below(const wallet_public::COMMAND_SWEEP_BELOW::request& req, wallet_public::COMMAND_SWEEP_BELOW::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_sign_transfer(const wallet_public::COMMAND_SIGN_TRANSFER::request& req, wallet_public::COMMAND_SIGN_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_submit_transfer(const wallet_public::COMMAND_SUBMIT_TRANSFER::request& req, wallet_public::COMMAND_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx); - bool on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::response& res, epee::json_rpc::error& er, connection_context& cntx); + bool on_search_for_transactions2(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_get_mining_history(const wallet_public::COMMAND_RPC_GET_MINING_HISTORY::request& req, wallet_public::COMMAND_RPC_GET_MINING_HISTORY::response& res, epee::json_rpc::error& er, connection_context& cntx); bool on_register_alias(const wallet_public::COMMAND_RPC_REGISTER_ALIAS::request& req, wallet_public::COMMAND_RPC_REGISTER_ALIAS::response& res, epee::json_rpc::error& er, connection_context& cntx); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index e9a95b88..aeed9669 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -188,6 +188,7 @@ bool wallets_manager::init_command_line(int argc, char* argv[], std::string& fai command_line::add_arg(desc_cmd_sett, arg_qt_dev_tools); command_line::add_arg(desc_cmd_sett, command_line::arg_no_predownload); command_line::add_arg(desc_cmd_sett, command_line::arg_force_predownload); + command_line::add_arg(desc_cmd_sett, command_line::arg_process_predownload_from_path); command_line::add_arg(desc_cmd_sett, command_line::arg_validate_predownload); command_line::add_arg(desc_cmd_sett, command_line::arg_predownload_link); command_line::add_arg(desc_cmd_only, command_line::arg_deeplink); @@ -1533,18 +1534,17 @@ std::string wallets_manager::transfer(uint64_t wallet_id, const view::transfer_p dsts.back().asset_id = d.asset_id; } + GET_WALLET_BY_ID(wallet_id, w); + if (payment_id.size()) { if (!currency::is_payment_id_size_ok(payment_id)) return API_RETURN_CODE_BAD_ARG_WRONG_PAYMENT_ID; // payment id is too big - if (!currency::set_payment_id_to_tx(attachments, payment_id)) + if (!currency::set_payment_id_to_tx(attachments, payment_id, w->get()->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))) return API_RETURN_CODE_INTERNAL_ERROR; } - GET_WALLET_BY_ID(wallet_id, w); - - //set transaction unlock time if it was specified by user uint64_t unlock_time = 0; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 628b40a0..71b544c1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,7 +28,7 @@ add_executable(net_load_tests_srv net_load_tests/srv.cpp) add_dependencies(coretests version) -target_link_libraries(coretests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(coretests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(functional_tests rpc wallet currency_core crypto common zlibstatic ethash libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(hash-tests crypto ethash) target_link_libraries(hash-target-tests crypto currency_core ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 16e564ef..f03bf1a2 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1055,6 +1055,7 @@ bool test_generator::construct_pow_block_with_alias_info_in_coinbase(const accou miner_tx.vout.clear(); tx_generation_context tx_gen_context{}; + tx_gen_context.set_tx_key(tx_key); tx_gen_context.resize(/* ZC ins: */ 0, /* OUTS: */ alias_cost != 0 ? 3 : 2); std::set deriv_cache; finalized_tx fin_tx_stub{}; diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index e1f95b08..98900f42 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1085,6 +1085,7 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(wallet_rpc_integrated_address); GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer); GENERATE_AND_PLAY(wallet_rpc_transfer); + GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4"); GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki); GENERATE_AND_PLAY(wallet_sending_to_integrated_address); diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index 93f394b0..28dda0e5 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -11,65 +11,6 @@ #include "wallet/wallet_debug_events_definitions.h" using namespace currency; - - - - - -/* - - -struct debug_context_event_1 -{ - int& i; - std::string& s; -}; - - - -//#define RAISE_DEBUG_EVENT dw.handle_type - - -void test_test() -{ - epee::misc_utils::events_dispatcher ed; - - //-------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------- - //thus code will be called in the tests - ed.SUBSCIRBE_DEBUG_EVENT([&](debug_context_event_1& d) - { - //here some operations - LOG_PRINT_L0("lala: " << d.i << d.s); - // - d.i = 10; - d.s = "33333"; - - }); - - - //-------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------- - //this code will be in the wallet and helper functions - - int i = 22; - std::string sss = "11111"; - - ed.RAISE_DEBUG_EVENT(debug_context_event_1{i, sss }); - - - LOG_PRINT_L0("lala: " << i << sss); -} -*/ - - - - - - - //------------------------------------------------------------------------------ #define AMOUNT_TO_TRANSFER_MULTIASSETS_BASIC (TESTS_DEFAULT_FEE) @@ -97,6 +38,7 @@ bool multiassets_basic_test::generate(std::vector& events) con DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks //TODO: Need to make sure REWIND_BLOCKS_N and other coretests codebase are capable of following hardfork4 rules //in this test hardfork4 moment moved to runtime section + //REWIND_BLOCKS_N_WITH_TIME(events, blk_2_inital, blk_0, alice_acc, 2); REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); DO_CALLBACK(events, "c1"); @@ -115,7 +57,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v alice_wlt->get_account().set_createtime(0); asset_descriptor_base adb = AUTO_VAL_INIT(adb); - adb.total_max_supply = 1000000000000000000; //1M coins + adb.total_max_supply = 10000000000000000000ULL; //1M coins adb.full_name = "Test coins"; adb.ticker = "TCT"; adb.decimal_point = 12; @@ -141,31 +83,13 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); - miner_wlt->refresh(); alice_wlt->refresh(); - uint64_t mined = 0; - std::unordered_map balances; - miner_wlt->balance(balances, mined); + CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances"); + CHECK_AND_ASSERT_MES(miner_wlt->balance() == uint64_t(17517225990000000000ULL), false, "Failed to find needed asset in result balances"); - auto it_asset = balances.find(asset_id); - auto it_native = balances.find(currency::native_coin_asset_id); - - - CHECK_AND_ASSERT_MES(it_asset != balances.end() && it_native != balances.end(), false, "Failed to find needed asset in result balances"); - CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances"); - CHECK_AND_ASSERT_MES(it_native->second.total == uint64_t(17517225990000000000), false, "Failed to find needed asset in result balances"); - - - balances.clear(); - alice_wlt->balance(balances, mined); - - it_asset = balances.find(asset_id); - it_native = balances.find(currency::native_coin_asset_id); - - CHECK_AND_ASSERT_MES(it_asset != balances.end(), false, "Failed to find needed asset in result balances"); - CHECK_AND_ASSERT_MES(it_native == balances.end(), false, "Failed to find needed asset in result balances"); - CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances"); + CHECK_AND_ASSERT_MES(alice_wlt->balance() == 0, false, "Failed to find needed asset in result balances"); + CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances"); miner_wlt->transfer(AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, alice_wlt->get_account().get_public_address(), asset_id); //pass over hardfork @@ -173,11 +97,9 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); alice_wlt->refresh(); - uint64_t last_alice_balances = alice_wlt->balance(asset_id, mined); + uint64_t last_alice_balances = alice_wlt->balance(asset_id); CHECK_AND_ASSERT_MES(last_alice_balances == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC + AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, false, "Failed to find needed asset in result balances"); - - { try { @@ -193,7 +115,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v } miner_wlt->refresh(); - uint64_t last_miner_balance = miner_wlt->balance(asset_id, mined); + uint64_t last_miner_balance = miner_wlt->balance(asset_id); asset_descriptor_base asset_info = AUTO_VAL_INIT(asset_info); @@ -211,7 +133,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v //test update function asset_info.meta_info = "{\"some\": \"info\"}"; miner_wlt->update_asset(asset_id, asset_info, tx); - r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 2); + r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, 2); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); asset_descriptor_base asset_info2 = AUTO_VAL_INIT(asset_info2); @@ -228,8 +150,8 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v miner_wlt->refresh(); alice_wlt->refresh(); - CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id, mined) == last_miner_balance + destinations[0].amount, false, "Miner balance wrong"); - CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id, mined) == last_alice_balances + destinations[1].amount, false, "Alice balance wrong"); + CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == last_miner_balance + destinations[0].amount, false, "Miner balance wrong"); + CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == last_alice_balances + destinations[1].amount, false, "Alice balance wrong"); asset_descriptor_base asset_info3 = AUTO_VAL_INIT(asset_info3); r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info3); @@ -242,7 +164,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); miner_wlt->refresh(); - CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id, mined) == destinations[0].amount, false, "Miner balance wrong"); + CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == destinations[0].amount, false, "Miner balance wrong"); asset_descriptor_base asset_info4 = AUTO_VAL_INIT(asset_info4); r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info4); @@ -252,10 +174,10 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v //------------------- tests that trying to break stuff ------------------- //tests that trying to break stuff - miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT([&](const wde_construct_tx_handle_asset_descriptor_operation& o) + miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT([&](const wde_construct_tx_after_asset_ownership_proof_generated& o) { - crypto::signature s = currency::null_sig; - o.pado->opt_proof = s; + //crypto::signature s = currency::null_sig; + o.pownership_proof->gss = crypto::generic_schnorr_sig_s{}; }); @@ -270,7 +192,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v c.get_tx_pool().purge_transactions(); miner_wlt->refresh(); - miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_DEBUG_EVENT(); + miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL(); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); @@ -317,17 +239,17 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v // check update_asset() with modified 'owner' - r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info); - CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info"); + //r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info); + //CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info"); - asset_info.owner = currency::keypair::generate().pub; - miner_wlt->update_asset(asset_id, asset_info, tx); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); - CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); - CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed - c.get_tx_pool().purge_transactions(); - miner_wlt->refresh(); + //asset_info.owner = currency::keypair::generate().pub; + //miner_wlt->update_asset(asset_id, asset_info, tx); + //CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + //r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); + //CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined"); + //CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed + //c.get_tx_pool().purge_transactions(); + //miner_wlt->refresh(); // check emmit_asset() with modified 'current_supply' @@ -346,13 +268,14 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v //------------------- tests that trying to break stuff ------------------- //test burn that burns more than tx has - miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_DEBUG_EVENT(); + miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL(); - miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT([&](const wde_construct_tx_handle_asset_descriptor_operation_before_seal& o) + miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT([&](const wde_construct_tx_handle_asset_descriptor_operation_before_burn& o) { o.pado->descriptor.current_supply -= 1000000; }); + miner_wlt->burn_asset(asset_id, 10000000000000, tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); @@ -360,8 +283,39 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed c.get_tx_pool().purge_transactions(); miner_wlt->refresh(); + miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL(); // + miner_wlt->transfer_asset_ownership(asset_id, alice_wlt->get_account().get_public_address().spend_public_key, tx); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c); + CHECK_AND_ASSERT_MES(r, false, "block with a bad tx was unexpectedly mined"); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed + + miner_wlt->refresh(); + alice_wlt->refresh(); + + auto miner_own_assets = miner_wlt->get_own_assets(); + auto alice_own_assets = alice_wlt->get_own_assets(); + CHECK_AND_ASSERT_MES(miner_own_assets.size() == 0, false, "Miner wlt still think he own asset"); + CHECK_AND_ASSERT_MES(alice_own_assets.size() == 1, false, "Alice still don't know she own asset"); + + //uint64_t balance_alice_native = alice_wlt->balance(); + //uint64_t balance_miner_native = miner_wlt->balance(); + uint64_t balance_alice_asset = alice_wlt->balance(asset_id); + uint64_t balance_miner_asset = miner_wlt->balance(asset_id); + + alice_wlt->emmit_asset(asset_id, destinations, tx); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); + + miner_wlt->refresh(); + alice_wlt->refresh(); + + CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == balance_miner_asset + destinations[0].amount, false, "Miner balance wrong"); + CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == balance_alice_asset + destinations[1].amount, false, "Alice balance wrong"); + + //TODO: attempt to emmmit from old key, attempt to emmit from more then max supply return true; } @@ -432,7 +386,7 @@ bool assets_and_explicit_native_coins_in_outs::generate(std::vector(pche->tx.extra) == 1, false, "tx_payer: incorrect count of items"); + return true; +} + +//------------------------------------------------------------------------------ + +wallet_rpc_exchange_suite::wallet_rpc_exchange_suite() +{ + REGISTER_CALLBACK_METHOD(wallet_rpc_exchange_suite, c1); +} + +bool wallet_rpc_exchange_suite::generate(std::vector& events) const +{ + m_accounts.resize(TOTAL_ACCS_COUNT); + account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time()); + DO_CALLBACK(events, "configure_core"); // default callback will initialize core runtime config with m_hardforks + + DO_CALLBACK(events, "c1"); + + return true; +} + + +struct transport +{ + tools::wallet_rpc_server& m_rpc_srv; + transport(tools::wallet_rpc_server& rpc_srv):m_rpc_srv(rpc_srv) + {} + epee::net_utils::http::http_response_info m_response; + + bool is_connected() { return true; } + template + bool connect(t_a ta, t_b tb, t_c tc) { return true; } + + template + bool invoke(const std::string uri, const std::string method_, const std::string& body, const epee::net_utils::http::http_response_info** ppresponse_info, const dummy_t& d) + { + epee::net_utils::http::http_request_info query_info; + query_info.m_URI = uri; + query_info.m_body = body; + tools::wallet_rpc_server::connection_context ctx; + bool r = m_rpc_srv.handle_http_request(query_info, m_response, ctx); + if (ppresponse_info) + *ppresponse_info = &m_response; + return r; + } +}; + +template +bool invoke_text_json_for_rpc(tools::wallet_rpc_server& srv, const std::string& method_name, const request_t& req, response_t& resp) +{ + transport tr(srv); + + bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, resp, tr); + return r; +} + +#include "wallet_rpc_tests_legacy_defs.h" + + +std::string gen_payment_id(tools::wallet_rpc_server& custody_wlt_rpc) +{ + pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request req = AUTO_VAL_INIT(req); + pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response resp = AUTO_VAL_INIT(resp); + bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp); + CHECK_AND_ASSERT_MES(r, "", "failed to call"); + return resp.payment_id; +} + +std::string get_integr_addr(tools::wallet_rpc_server& custody_wlt_rpc, const std::string payment_id) +{ + pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request req = AUTO_VAL_INIT(req); + req.payment_id = payment_id; + pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response resp = AUTO_VAL_INIT(resp); + bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp); + CHECK_AND_ASSERT_MES(r, "", "failed to call"); + return resp.integrated_address; +} + +#define TRANSFER_COMMENT "SSDVSf" +std::string transfer_(std::shared_ptr wlt, const std::string& address, uint64_t amount) +{ + tools::wallet_rpc_server custody_wlt_rpc(wlt); + pre_hf4_api::COMMAND_RPC_TRANSFER::request tr_req = AUTO_VAL_INIT(tr_req); + tr_req.comment = TRANSFER_COMMENT; + tr_req.destinations.resize(1); + tr_req.destinations.back().address = address; + tr_req.destinations.back().amount = amount; + tr_req.fee = TX_DEFAULT_FEE; + pre_hf4_api::COMMAND_RPC_TRANSFER::response tr_resp = AUTO_VAL_INIT(tr_resp); + bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "transfer", tr_req, tr_resp); + CHECK_AND_ASSERT_MES(r, "", "failed to call"); + return tr_resp.tx_hash; +} + +bool test_payment_ids_generation(tools::wallet_rpc_server& custody_wlt_rpc) +{ + //check make_integrated_address/split_integrated_address +//check auto generated payment_id + pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request req = AUTO_VAL_INIT(req); + pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response resp = AUTO_VAL_INIT(resp); + bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + //custody_wlt_rpc.handle_http_request() + + pre_hf4_api::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request req2 = AUTO_VAL_INIT(req2); + req2.integrated_address = resp.integrated_address; + pre_hf4_api::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response resp2 = AUTO_VAL_INIT(resp2); + r = invoke_text_json_for_rpc(custody_wlt_rpc, "split_integrated_address", req2, resp2); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + + CHECK_AND_ASSERT_MES(resp2.payment_id == resp.payment_id, false, "generated paymentids missmatched"); + + //check manually set payment_id + req.payment_id = resp.payment_id; + r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + //custody_wlt_rpc.handle_http_request() + req2.integrated_address = resp.integrated_address; + r = invoke_text_json_for_rpc(custody_wlt_rpc, "split_integrated_address", req2, resp2); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + + CHECK_AND_ASSERT_MES(resp2.payment_id == req.payment_id, false, "generated paymentids missmatched"); + return true; +} + +bool wallet_rpc_exchange_suite::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + + bool r = false; + account_base alice_acc, bob_acc, carol_acc, custody_acc; + alice_acc.generate(); + bob_acc.generate(); + carol_acc.generate(); + custody_acc.generate(); + + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, alice_acc); + std::shared_ptr bob_wlt = init_playtime_test_wallet(events, c, bob_acc); + std::shared_ptr carol_wlt = init_playtime_test_wallet(events, c, carol_acc); + std::shared_ptr custody_wlt = init_playtime_test_wallet(events, c, custody_acc); + + r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, 3); + r = mine_next_pow_blocks_in_playtime(bob_wlt->get_account().get_public_address(), c, 3); + r = mine_next_pow_blocks_in_playtime(carol_wlt->get_account().get_public_address(), c, 3); + //r = mine_next_pow_blocks_in_playtime(custody_wlt->get_account().get_public_address(), c, 3); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + + // wallet RPC server + tools::wallet_rpc_server custody_wlt_rpc(custody_wlt); + + r = test_payment_ids_generation(custody_wlt_rpc); + CHECK_AND_ASSERT_MES(r, false, "test_payment_ids_generation() failed "); + //====================================================================== + std::string alice_payment_id = gen_payment_id(custody_wlt_rpc); + std::string bob_payment_id = gen_payment_id(custody_wlt_rpc); + std::string carol_payment_id = gen_payment_id(custody_wlt_rpc); + + // generate payment id's for each wallet and deposit + custody_wlt->refresh(); + alice_wlt->refresh(); + bob_wlt->refresh(); + carol_wlt->refresh(); + +#define TRANSFER_AMOUNT COIN / 10 + + std::string alice_tx1 = transfer_(alice_wlt, get_integr_addr(custody_wlt_rpc, alice_payment_id), TRANSFER_AMOUNT); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); + + std::string bob_tx1 = transfer_(bob_wlt, get_integr_addr(custody_wlt_rpc, bob_payment_id), TRANSFER_AMOUNT); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); + + std::string bob_tx2 = transfer_(bob_wlt, get_integr_addr(custody_wlt_rpc, bob_payment_id), TRANSFER_AMOUNT); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); + + std::string carol_tx1 = transfer_(carol_wlt, get_integr_addr(custody_wlt_rpc, carol_payment_id), TRANSFER_AMOUNT); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); + + std::string carol_tx2 = transfer_(carol_wlt, get_integr_addr(custody_wlt_rpc, carol_payment_id), TRANSFER_AMOUNT); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); + + std::string carol_tx3 = transfer_(carol_wlt, get_integr_addr(custody_wlt_rpc, carol_payment_id), TRANSFER_AMOUNT); + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1); + + CHECK_AND_ASSERT_MES(alice_tx1.size() + && bob_tx1.size() + && bob_tx2.size() + && carol_tx1.size() + && carol_tx2.size() + && carol_tx3.size(), + false, "One of deposit transactions wan't created" + ); + + r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + custody_wlt->refresh(); + pre_hf4_api::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request req = AUTO_VAL_INIT(req); + req.update_provision_info = true; + req.count = 10; + + pre_hf4_api::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response resp = AUTO_VAL_INIT(resp); + r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_recent_txs_and_info", req, resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + +#define CHECK_RESPONSE_EQUAL(condition) CHECK_AND_ASSERT_MES((condition), false, "Failed check"); + + CHECK_RESPONSE_EQUAL(resp.pi.balance == 600000000000); + CHECK_RESPONSE_EQUAL(resp.pi.unlocked_balance == 600000000000); + CHECK_RESPONSE_EQUAL(resp.pi.transfers_count == 6); + CHECK_RESPONSE_EQUAL(resp.total_transfers == 6); + CHECK_RESPONSE_EQUAL(resp.transfers.size() == 6); + CHECK_RESPONSE_EQUAL(resp.transfers[0].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[0].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[0].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[0].payment_id) == carol_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[0].tx_hash) == carol_tx3); + + CHECK_RESPONSE_EQUAL(resp.transfers[1].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[1].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[1].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[1].payment_id) == carol_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[1].tx_hash) == carol_tx2); + + CHECK_RESPONSE_EQUAL(resp.transfers[2].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[2].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[2].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[2].payment_id) == carol_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[2].tx_hash) == carol_tx1); + + CHECK_RESPONSE_EQUAL(resp.transfers[3].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[3].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[3].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[3].payment_id) == bob_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[3].tx_hash) == bob_tx2); + + CHECK_RESPONSE_EQUAL(resp.transfers[4].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[4].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[4].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[4].payment_id) == bob_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[4].tx_hash) == bob_tx1); + + CHECK_RESPONSE_EQUAL(resp.transfers[5].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[5].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[5].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[5].payment_id) == alice_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[5].tx_hash) == alice_tx1); + + + req.count = 10; + req.offset = 2; + r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_recent_txs_and_info", req, resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + + CHECK_RESPONSE_EQUAL(resp.pi.balance == 600000000000); + CHECK_RESPONSE_EQUAL(resp.pi.unlocked_balance == 600000000000); + CHECK_RESPONSE_EQUAL(resp.pi.transfers_count == 6); + CHECK_RESPONSE_EQUAL(resp.total_transfers == 6); + CHECK_RESPONSE_EQUAL(resp.transfers.size() == 4); + CHECK_RESPONSE_EQUAL(resp.transfers[0].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[0].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[0].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[0].payment_id) == carol_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[0].tx_hash) == carol_tx1); + + CHECK_RESPONSE_EQUAL(resp.transfers[1].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[1].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[1].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[1].payment_id) == bob_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[1].tx_hash) == bob_tx2); + + CHECK_RESPONSE_EQUAL(resp.transfers[2].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[2].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[2].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[2].payment_id) == bob_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[2].tx_hash) == bob_tx1); + + CHECK_RESPONSE_EQUAL(resp.transfers[3].comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(resp.transfers[3].amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(resp.transfers[3].is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[3].payment_id) == alice_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(resp.transfers[3].tx_hash) == alice_tx1); + + //getbalance + pre_hf4_api::COMMAND_RPC_GET_BALANCE::request gb_req = AUTO_VAL_INIT(gb_req); + pre_hf4_api::COMMAND_RPC_GET_BALANCE::response gb_resp = AUTO_VAL_INIT(gb_resp); + r = invoke_text_json_for_rpc(custody_wlt_rpc, "getbalance", gb_req, gb_resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + CHECK_RESPONSE_EQUAL(gb_resp.balance == 600000000000); + CHECK_RESPONSE_EQUAL(gb_resp.unlocked_balance == 600000000000); + + //get_wallet_info + pre_hf4_api::COMMAND_RPC_GET_WALLET_INFO::request gwi_req = AUTO_VAL_INIT(gwi_req); + pre_hf4_api::COMMAND_RPC_GET_WALLET_INFO::response gwi_resp = AUTO_VAL_INIT(gwi_resp); + r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_wallet_info", gwi_req, gwi_resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + CHECK_RESPONSE_EQUAL(gwi_resp.current_height == 35); + CHECK_RESPONSE_EQUAL(gwi_resp.transfer_entries_count == 6); + CHECK_RESPONSE_EQUAL(gwi_resp.transfers_count == 6); + CHECK_RESPONSE_EQUAL(gwi_resp.address == custody_wlt->get_account().get_public_address_str()); + + + //search_for_transactions + pre_hf4_api::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request st_req = AUTO_VAL_INIT(st_req); + st_req.filter_by_height = false; + st_req.in = true; + st_req.out = true; + st_req.pool = true; + st_req.tx_id = resp.transfers[1].tx_hash; //bob_tx2 + pre_hf4_api::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response st_resp = AUTO_VAL_INIT(st_resp); + r = invoke_text_json_for_rpc(custody_wlt_rpc, "search_for_transactions", st_req, st_resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + //TODO: add more cases for search transaction in pool, in and out + + + CHECK_RESPONSE_EQUAL(st_resp.in.size() == 1); + CHECK_RESPONSE_EQUAL(st_resp.in.begin()->comment == TRANSFER_COMMENT); + CHECK_RESPONSE_EQUAL(st_resp.in.begin()->amount == TRANSFER_AMOUNT); + CHECK_RESPONSE_EQUAL(st_resp.in.begin()->is_income == true); + CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(st_resp.in.begin()->payment_id) == bob_payment_id); + CHECK_RESPONSE_EQUAL(boost::lexical_cast(st_resp.in.begin()->tx_hash) == bob_tx2); + + + //get_payments + pre_hf4_api::COMMAND_RPC_GET_PAYMENTS::request gps_req = AUTO_VAL_INIT(gps_req); + gps_req.payment_id = carol_payment_id; + pre_hf4_api::COMMAND_RPC_GET_PAYMENTS::response gps_resp = AUTO_VAL_INIT(gps_resp); + r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_payments", gps_req, gps_resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + + { + //sort by block_height to have deterministic order + gps_resp.payments.sort([&](const pre_hf4_api::payment_details& a, const pre_hf4_api::payment_details& b) {return a.block_height < b.block_height; }); + + CHECK_RESPONSE_EQUAL(gps_resp.payments.size() == 3); + auto it = gps_resp.payments.begin(); + CHECK_RESPONSE_EQUAL(it->amount == 100000000000); + CHECK_RESPONSE_EQUAL(it->payment_id == carol_payment_id); + CHECK_RESPONSE_EQUAL(it->block_height == 23); + it++; + CHECK_RESPONSE_EQUAL(it->amount == 100000000000); + CHECK_RESPONSE_EQUAL(it->payment_id == carol_payment_id); + CHECK_RESPONSE_EQUAL(it->block_height == 24); + it++; + CHECK_RESPONSE_EQUAL(it->amount == 100000000000); + CHECK_RESPONSE_EQUAL(it->payment_id == carol_payment_id); + CHECK_RESPONSE_EQUAL(it->block_height == 25); + } + + + + //get_bulk_payments + pre_hf4_api::COMMAND_RPC_GET_BULK_PAYMENTS::request gbps_req = AUTO_VAL_INIT(gbps_req); + gbps_req.payment_ids.push_back(bob_payment_id); + gbps_req.payment_ids.push_back(alice_payment_id); + pre_hf4_api::COMMAND_RPC_GET_BULK_PAYMENTS::response gbps_resp = AUTO_VAL_INIT(gbps_resp); + r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_bulk_payments", gbps_req, gbps_resp); + CHECK_AND_ASSERT_MES(r, false, "failed to call"); + + { + //sort by block_height to have deterministic order + gbps_resp.payments.sort([&](const pre_hf4_api::payment_details& a, const pre_hf4_api::payment_details& b) {return a.block_height < b.block_height; }); + + CHECK_RESPONSE_EQUAL(gbps_resp.payments.size() == 3); + auto it = gbps_resp.payments.begin(); + CHECK_RESPONSE_EQUAL(it->amount == 100000000000); + CHECK_RESPONSE_EQUAL(it->payment_id == alice_payment_id); + CHECK_RESPONSE_EQUAL(it->block_height == 20); + it++; + CHECK_RESPONSE_EQUAL(it->amount == 100000000000); + CHECK_RESPONSE_EQUAL(it->payment_id == bob_payment_id); + CHECK_RESPONSE_EQUAL(it->block_height == 21); + it++; + CHECK_RESPONSE_EQUAL(it->amount == 100000000000); + CHECK_RESPONSE_EQUAL(it->payment_id == bob_payment_id); + CHECK_RESPONSE_EQUAL(it->block_height == 22); + } + return true; } diff --git a/tests/core_tests/wallet_rpc_tests.h b/tests/core_tests/wallet_rpc_tests.h index 32d71571..aa6e9b5e 100644 --- a/tests/core_tests/wallet_rpc_tests.h +++ b/tests/core_tests/wallet_rpc_tests.h @@ -28,3 +28,16 @@ struct wallet_rpc_transfer : public wallet_test bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; + +/* + Tests to make sure api for exchanges didn't change after HF4(Zarcanum) + testing api: get_recent_txs_and_info, make_integrated_address, + getbalance, get_wallet_info, get_transfer_by_txid, +*/ +struct wallet_rpc_exchange_suite : public wallet_test +{ + wallet_rpc_exchange_suite(); + 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/wallet_rpc_tests_legacy_defs.h b/tests/core_tests/wallet_rpc_tests_legacy_defs.h new file mode 100644 index 00000000..f4994a5a --- /dev/null +++ b/tests/core_tests/wallet_rpc_tests_legacy_defs.h @@ -0,0 +1,431 @@ +// Copyright (c) 2014-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 + +namespace pre_hf4_api +{ + struct COMMAND_RPC_MAKE_INTEGRATED_ADDRESS + { + struct request + { + std::string payment_id; // hex-encoded + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payment_id) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string integrated_address; + std::string payment_id; // hex-encoded + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(integrated_address) + KV_SERIALIZE(payment_id) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS + { + struct request + { + std::string integrated_address; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(integrated_address) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string standard_address; + std::string payment_id; // hex-encoded + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(standard_address) + KV_SERIALIZE(payment_id) + END_KV_SERIALIZE_MAP() + }; + }; + + struct transfer_destination + { + uint64_t amount; + std::string address; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE(address) + END_KV_SERIALIZE_MAP() + }; + + struct tx_service_attachment + { + std::string service_id; //string identifying service which addressed this attachment + std::string instruction; //string identifying specific instructions for service/way to interpret data + std::string body; //any data identifying service, options etc + std::vector security; //some of commands need proof of owner + uint8_t flags; //special flags (ex: TX_SERVICE_ATTACHMENT_ENCRYPT_BODY), see below + + BEGIN_SERIALIZE() + FIELD(service_id) + FIELD(instruction) + FIELD(body) + FIELD(security) + FIELD(flags) + END_SERIALIZE() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(service_id) + KV_SERIALIZE(instruction) + KV_SERIALIZE_BLOB_AS_HEX_STRING(body) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(security) + KV_SERIALIZE(flags) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_TRANSFER + { + struct request + { + std::list destinations; + uint64_t fee; + uint64_t mixin; + //uint64_t unlock_time; + std::string payment_id; // hex-encoded + std::string comment; + bool push_payer; + bool hide_receiver; + std::vector service_entries; + bool service_entries_permanent; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(destinations) + KV_SERIALIZE(fee) + KV_SERIALIZE(mixin) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(comment) + KV_SERIALIZE(push_payer) + KV_SERIALIZE(hide_receiver) + KV_SERIALIZE(service_entries) + KV_SERIALIZE(service_entries_permanent) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string tx_hash; + std::string tx_unsigned_hex; // for cold-signing process + uint64_t tx_size; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_unsigned_hex) + KV_SERIALIZE(tx_size) + END_KV_SERIALIZE_MAP() + }; + }; + + struct wallet_transfer_info_details + { + std::list rcv; + std::list spn; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(rcv) + KV_SERIALIZE(spn) + END_KV_SERIALIZE_MAP() + + }; + + struct wallet_transfer_info + { + uint64_t amount; + uint64_t timestamp; + crypto::hash tx_hash; + uint64_t height; //if height == 0 then tx is unconfirmed + uint64_t unlock_time; + uint32_t tx_blob_size; + std::string payment_id; + std::vector remote_addresses; //optional + std::vector recipients_aliases; //optional + std::string comment; + bool is_income; + bool is_service; + bool is_mixing; + bool is_mining; + uint64_t tx_type; + wallet_transfer_info_details td; + std::vector service_entries; + //not included in streaming serialization + uint64_t fee; + bool show_sender; + //std::vector contract; //not traxking this part + uint16_t extra_flags; + uint64_t transfer_internal_index; + + + //not included in kv serialization map + currency::transaction tx; + std::vector selected_indicies; + std::list marketplace_entries; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE_POD_AS_HEX_STRING(tx_hash) + KV_SERIALIZE(height) + KV_SERIALIZE(unlock_time) + KV_SERIALIZE(tx_blob_size) + KV_SERIALIZE_BLOB_AS_HEX_STRING(payment_id) + KV_SERIALIZE(remote_addresses) + KV_SERIALIZE(recipients_aliases) + KV_SERIALIZE(comment) + KV_SERIALIZE(is_income) + KV_SERIALIZE(timestamp) + KV_SERIALIZE(td) + KV_SERIALIZE(fee) + KV_SERIALIZE(is_service) + KV_SERIALIZE(is_mixing) + KV_SERIALIZE(is_mining) + KV_SERIALIZE(tx_type) + KV_SERIALIZE(show_sender) + //KV_SERIALIZE(contract) + KV_SERIALIZE(service_entries) + KV_SERIALIZE(transfer_internal_index) + END_KV_SERIALIZE_MAP() + }; + + struct wallet_provision_info + { + uint64_t transfers_count; + uint64_t transfer_entries_count; + uint64_t balance; + uint64_t unlocked_balance; + uint64_t curent_height; + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(transfers_count) + KV_SERIALIZE(transfer_entries_count) + KV_SERIALIZE(balance) + KV_SERIALIZE(unlocked_balance) + KV_SERIALIZE(curent_height) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_GET_RECENT_TXS_AND_INFO + { + struct request + { + + /* + if offset is 0, then GET_RECENT_TXS_AND_INFO return + unconfirmed transactions as the first first items of "transfers", + this unconfirmed transactions is not counted regarding "count" parameter + */ + uint64_t offset; + uint64_t count; + + /* + need_to_get_info - should backend re-calculate balance(could be relatively heavy, + and not needed when getting long tx history with multiple calls + of GET_RECENT_TXS_AND_INFO with offsets) + */ + bool update_provision_info; + bool exclude_mining_txs; + bool exclude_unconfirmed; + std::string order; // "FROM_BEGIN_TO_END" or "FROM_END_TO_BEGIN" + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(offset) + KV_SERIALIZE(count) + KV_SERIALIZE(update_provision_info) + KV_SERIALIZE(exclude_mining_txs) + KV_SERIALIZE(exclude_unconfirmed) + KV_SERIALIZE(order) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + wallet_provision_info pi; + std::vector transfers; + uint64_t total_transfers; + uint64_t last_item_index; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(pi) + KV_SERIALIZE(transfers) + KV_SERIALIZE(total_transfers) + KV_SERIALIZE(last_item_index) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_BALANCE + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + uint64_t balance; + uint64_t unlocked_balance; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(balance) + KV_SERIALIZE(unlocked_balance) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_GET_WALLET_INFO + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string address; + std::string path; + uint64_t transfers_count; + uint64_t transfer_entries_count; + bool is_whatch_only; + std::vector utxo_distribution; + uint64_t current_height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(address) + KV_SERIALIZE(path) + KV_SERIALIZE(transfers_count) + KV_SERIALIZE(transfer_entries_count) + KV_SERIALIZE(is_whatch_only) + KV_SERIALIZE(utxo_distribution) + KV_SERIALIZE(current_height) + END_KV_SERIALIZE_MAP() + }; + }; + + + struct COMMAND_RPC_SEARCH_FOR_TRANSACTIONS + { + struct request + { + crypto::hash tx_id; + bool in; + bool out; + //bool pending; + //bool failed; + bool pool; + bool filter_by_height; + uint64_t min_height; + uint64_t max_height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(tx_id) + KV_SERIALIZE(in) + KV_SERIALIZE(out) + //KV_SERIALIZE(pending) + //KV_SERIALIZE(failed) + KV_SERIALIZE(pool) + KV_SERIALIZE(filter_by_height) + KV_SERIALIZE(min_height) + KV_SERIALIZE(max_height) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list in; + std::list out; + //std::list pending; + //std::list failed; + std::list pool; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(in) + KV_SERIALIZE(out) + //KV_SERIALIZE(pending) + //KV_SERIALIZE(failed) + KV_SERIALIZE(pool) + END_KV_SERIALIZE_MAP() + }; + }; + + struct payment_details + { + std::string payment_id; + std::string tx_hash; + uint64_t amount; + uint64_t block_height; + uint64_t unlock_time; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payment_id) + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(amount) + KV_SERIALIZE(block_height) + KV_SERIALIZE(unlock_time) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_GET_PAYMENTS + { + struct request + { + std::string payment_id; // hex-encoded + bool allow_locked_transactions; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payment_id) + KV_SERIALIZE(allow_locked_transactions) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list payments; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payments) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_GET_BULK_PAYMENTS + { + struct request + { + std::vector payment_ids; + uint64_t min_block_height; + bool allow_locked_transactions; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payment_ids) + KV_SERIALIZE(min_block_height) + KV_SERIALIZE(allow_locked_transactions) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::list payments; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(payments) + END_KV_SERIALIZE_MAP() + }; + }; + +} diff --git a/tests/functional_tests/core_concurrency_test.cpp b/tests/functional_tests/core_concurrency_test.cpp index 0173f093..c0b70781 100644 --- a/tests/functional_tests/core_concurrency_test.cpp +++ b/tests/functional_tests/core_concurrency_test.cpp @@ -65,6 +65,7 @@ bool create_block_template_manually(const currency::block& prev_block, boost::mu // make things really simple by assuming block size is less than CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE size_t median_size = 0; uint64_t block_reward_without_fee = 0; + uint64_t block_reward = 0; bool r = construct_miner_tx(get_block_height(prev_block) + 1, median_size, @@ -75,6 +76,7 @@ bool create_block_template_manually(const currency::block& prev_block, boost::mu miner_addr, result.miner_tx, block_reward_without_fee, + block_reward, TRANSACTION_VERSION_PRE_HF4); CHECK_AND_ASSERT_MES(r, false, "construct_miner_tx failed"); diff --git a/tests/unit_tests/test_format_utils.cpp b/tests/unit_tests/test_format_utils.cpp index 890f98ec..0e277222 100644 --- a/tests/unit_tests/test_format_utils.cpp +++ b/tests/unit_tests/test_format_utils.cpp @@ -14,8 +14,9 @@ TEST(parse_and_validate_tx_extra, is_correct_parse_and_validate_tx_extra) currency::account_base acc; acc.generate(); currency::blobdata b = "dsdsdfsdfsf"; - uint64_t block_reward_without_fee = 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, TRANSACTION_VERSION_PRE_HF4, b, 1); + 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); ASSERT_TRUE(r); crypto::public_key tx_pub_key; r = currency::parse_and_validate_tx_extra(tx, tx_pub_key); @@ -27,8 +28,9 @@ TEST(parse_and_validate_tx_extra, is_correct_extranonce_too_big) currency::account_base acc; acc.generate(); currency::blobdata b(260, 0); - uint64_t block_reward_without_fee = 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, TRANSACTION_VERSION_PRE_HF4, b, 1); + 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); ASSERT_FALSE(r); } @@ -56,7 +58,7 @@ TEST(parse_and_validate_tx_extra, test_payment_ids) ASSERT_TRUE(r); std::string h2; - r = currency::get_payment_id_from_tx(tx.attachment, h2); + r = currency::get_payment_id_from_decrypted_container(tx.attachment, h2); ASSERT_TRUE(r); ASSERT_EQ(h, h2); diff --git a/utils/build_script_linux_appimage.sh b/utils/build_script_linux_appimage.sh index dad4b69e..21ffc53e 100755 --- a/utils/build_script_linux_appimage.sh +++ b/utils/build_script_linux_appimage.sh @@ -51,7 +51,7 @@ echo "Building...." rm -rf build; mkdir -p build/release; cd build/release; -cmake $testnet_def -D STATIC=true -D ARCH=x86-64 -D BUILD_GUI=TRUE -D OPENSSL_ROOT_DIR="$OPENSSL_ROOT_DIR" -D CMAKE_PREFIX_PATH="$QT_PREFIX_PATH" -D CMAKE_BUILD_TYPE=Release ../.. +cmake $testnet_def -D STATIC=true -D ARCH=x86-64 -D DISABLE_TOR=TRUE -D BUILD_GUI=TRUE -D OPENSSL_ROOT_DIR="$OPENSSL_ROOT_DIR" -D CMAKE_PREFIX_PATH="$QT_PREFIX_PATH" -D CMAKE_BUILD_TYPE=Release ../.. if [ $? -ne 0 ]; then echo "Failed to run cmake" exit 1