diff --git a/CMakeLists.txt b/CMakeLists.txt index e320fafc..c480300f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,11 @@ set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers") set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect submodule)") set(TESTNET FALSE CACHE BOOL "Compile for testnet") set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon") +set(USE_BITCOIN_SECP256K1_FOR_ECDSA FALSE CACHE BOOL "Use bitcoin-secp256k1 library for validating ECDSA(instead of OpenSSL)") +if(NOT USE_BITCOIN_SECP256K1_FOR_ECDSA) + add_definitions(-DUSE_OPEN_SSL_FOR_ECDSA) +endif() + include_directories(src contrib/eos_portable_archive contrib contrib/epee/include contrib/jwt-cpp/include ${OPENSSL_INCLUDE_DIR} "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib") @@ -89,6 +94,7 @@ endif() if(CAKEWALLET) message("NOTICE: Building libraries for CAKEWALLET") add_definitions(-DCAKEWALLET) + add_definitions(-DDISABLE_PFR_SERIALIZATION_SELFCHECK) endif() set(OPENSSL_USE_STATIC_LIBS TRUE) # link statically @@ -240,8 +246,12 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS") #set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}") #set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}") elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") - set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/") - set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a") + if(CAKEWALLET) + find_package(Boost 1.71 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale) + else() + set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/") + set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a") + endif() set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC") elseif(APPLE) @@ -259,7 +269,7 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/contrib/e if(MINGW) set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") elseif(NOT MSVC) - if(NOT APPLE) + if(NOT APPLE AND NOT CAKEWALLET) set(Boost_LIBRARIES "${Boost_LIBRARIES};") if(STATIC) message("NOTICE: Including static ICU libraries") diff --git a/README.md b/README.md index e4515a47..655e780a 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,10 @@ Be sure to clone the repository properly:\ |--|--|--|--| | gcc (Linux) | 5.4.0 | 9.4.0 | 12.3.0 | | llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 | -| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2019 (16.11.34) | 2022 (17.9.5) | +| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2019 (16.11.34) | 2022 (17.11.5) | | [XCode](https://developer.apple.com/downloads/) (macOS) | 12.3 | 14.3 | 15.2 | | [CMake](https://cmake.org/download/) | 3.15.5 | 3.26.3 | 3.29.0 | -| [Boost](https://www.boost.org/users/download/) | 1.70 | 1.70 | 1.84 | +| [Boost](https://www.boost.org/users/download/) | 1.75 | 1.84 | 1.84 | | [OpenSSL](https://www.openssl.org/source/) [(win)](https://slproweb.com/products/Win32OpenSSL.html) | 1.1.1n | 1.1.1w | 1.1.1w | | [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 5.8.0 | 5.11.2 | 5.15.2 | @@ -52,10 +52,9 @@ Recommended OS versions: Ubuntu 20.04, 22.04 LTS. 3. Download and build Boost\ (Assuming you have cloned Zano into the 'zano' folder. If you used a different location for Zano, **edit line 4** accordingly.) - curl -OL https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/boost_1_70_0.tar.bz2 - echo "430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 boost_1_70_0.tar.bz2" | shasum -c && tar -xjf boost_1_70_0.tar.bz2 - rm boost_1_70_0.tar.bz2 && cd boost_1_70_0 - patch -p0 < ../zano/utils/boost_1.70_gcc_8.patch || cd .. + curl -OL https://boostorg.jfrog.io/artifactory/main/release/1.84.0/source/boost_1_84_0.tar.bz2 + echo "cc4b893acf645c9d4b698e9a0f08ca8846aa5d6c68275c14c3e7949c24109454 boost_1_84_0.tar.bz2" | shasum -c && tar -xjf boost_1_84_0.tar.bz2 + rm boost_1_84_0.tar.bz2 && cd boost_1_84_0 ./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer,log ./b2 && cd .. Make sure that you see "The Boost C++ Libraries were successfully built!" message at the end. @@ -88,13 +87,13 @@ For instance, by adding the following lines to `~/.bashrc` [*server version*] - export BOOST_ROOT=/home/user/boost_1_70_0 + export BOOST_ROOT=/home/user/boost_1_84_0 export OPENSSL_ROOT_DIR=/home/user/openssl [*GUI version*] - export BOOST_ROOT=/home/user/boost_1_70_0 + export BOOST_ROOT=/home/user/boost_1_84_0 export OPENSSL_ROOT_DIR=/home/user/openssl export QT_PREFIX_PATH=/home/user/Qt5.11.2/5.11.2/gcc_64 @@ -169,3 +168,14 @@ To build GUI application: 2. Revise building script, comment out unwanted steps and run it: `utils/build_script_mac_osx.sh` 3. The application should be here: `/buid_mac_osx_64/release/src` +
+
+ +## Supporting project/donations + +ZANO @dev
+BTC bc1qpa8w8eaehlplfepmnzpd7v9j046899nktxnkxp
+BCH qqgq078vww5exd9kt3frx6krdyznmp80hcygzlgqzd
+ETH 0x206c52b78141498e74FF074301ea90888C40c178
+XMR 45gp9WTobeB5Km3kLQgVmPJkvm9rSmg4gdyHheXqXijXYMjUY48kLgL7QEz5Ar8z9vQioQ68WYDKsQsjAEonSeFX4UeLSiX
+ diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index c1a5535f..842f905c 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -5,13 +5,22 @@ add_subdirectory(zlib) add_subdirectory(db) add_subdirectory(ethereum) -option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." OFF) -option(SECP256K1_BUILD_TESTS "Build tests." OFF) -option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." OFF) -option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." OFF) -option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) -set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1) -add_subdirectory(bitcoin-secp256k1) +if(USE_BITCOIN_SECP256K1_FOR_ECDSA) + option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." OFF) + option(SECP256K1_BUILD_TESTS "Build tests." OFF) + option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." OFF) + option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." OFF) + option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) + set_property(GLOBAL PROPERTY CTEST_TARGETS_ADDED 1) + + if(STATIC) + set(SECP256K1_DISABLE_SHARED ON CACHE BOOL "Disable shared library for secp256k1") + set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static libraries by default" FORCE) + endif() + add_subdirectory(bitcoin-secp256k1) + set_property(TARGET secp256k1 PROPERTY FOLDER "contrib") + set_property(TARGET secp256k1_precomputed PROPERTY FOLDER "contrib") +endif() if( NOT DISABLE_TOR) add_subdirectory(tor-connect) @@ -31,8 +40,6 @@ set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib") set_property(TARGET zlibstatic PROPERTY FOLDER "contrib") set_property(TARGET mdbx PROPERTY FOLDER "contrib") set_property(TARGET lmdb PROPERTY FOLDER "contrib") -set_property(TARGET secp256k1 PROPERTY FOLDER "contrib") -set_property(TARGET secp256k1_precomputed PROPERTY FOLDER "contrib") if( NOT DISABLE_TOR) set_property(TARGET tor-connect PROPERTY FOLDER "contrib") diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 376af660..e32a9bc5 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019, Zano Project +// Copyright (c) 2019-2024, Zano Project // Copyright (c) 2019, anonimal // Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net // All rights reserved. @@ -90,7 +90,7 @@ DISABLE_VS_WARNINGS(4100) #define LOG_JOURNAL_MAX_ELEMENTS 100 #ifdef _DEBUG - #define _ASSERTE__(expr) if(!expr) {__debugbreak();} + #define _ASSERTE__(expr) if(!(expr)) {__debugbreak();} #else #define _ASSERTE__(expr) #endif diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index b4466ad4..9e1ad044 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -282,8 +282,15 @@ namespace epee { namespace http { struct i_chain_handler { + virtual bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info, + epee::net_utils::connection_context_base& conn_context, bool& call_found, documentation& docs = epee::net_utils::http::i_chain_handler::m_empty_documentation) + { + return this->handle_http_request_map(query_info, response_info, conn_context, call_found, docs); + } + virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info, epee::net_utils::connection_context_base& m_conn_context, bool& call_found, documentation& docs = epee::net_utils::http::i_chain_handler::m_empty_documentation) = 0; + static inline documentation m_empty_documentation; }; @@ -365,7 +372,7 @@ namespace epee { LOG_PRINT( "[HTTP/BIN][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ } -#define CHAIN_TO_PHANDLER(pi_chain_handler) else if (pi_chain_handler && pi_chain_handler->handle_http_request_map(query_info, response_info, m_conn_context, call_found, docs) && call_found) { return true;} +#define CHAIN_TO_PHANDLER(pi_chain_handler) else if (pi_chain_handler && pi_chain_handler->handle_http_request(query_info, response_info, m_conn_context, call_found, docs) && call_found) { return true;} #define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);call_found = true;} diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index d0d7c408..1bd2db1c 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -360,8 +360,12 @@ namespace epee template< class t_type_stored, class t_type, class t_storage, typename cb_serialize> static bool serialize_ephemeral(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname, cb_serialize cb_s) { - t_type_stored a = cb_s(d); - return epee::serialization::selector::serialize(a, stg, hparent_section, pname); + t_type_stored a = AUTO_VAL_INIT(a); + bool add_val = cb_s(d, a); + if (add_val) + return epee::serialization::selector::serialize(a, stg, hparent_section, pname); + else + return true; } }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 563b4266..4505b8f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,8 +116,13 @@ else() endif() add_library(crypto ${CRYPTO}) -add_dependencies(crypto secp256k1) -target_link_libraries(crypto secp256k1) +if(USE_BITCOIN_SECP256K1_FOR_ECDSA) + add_dependencies(crypto secp256k1) + target_link_libraries(crypto secp256k1) +else() + add_dependencies(crypto OpenSSL::Crypto) + target_link_libraries(crypto OpenSSL::Crypto) +endif() add_library(currency_core ${CURRENCY_CORE}) add_dependencies(currency_core version ${PCH_LIB_NAME}) diff --git a/src/common/boost_serialization_maps.h b/src/common/boost_serialization_maps.h index 5fbecea0..f6704b95 100644 --- a/src/common/boost_serialization_maps.h +++ b/src/common/boost_serialization_maps.h @@ -3,7 +3,10 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once - +#include +#ifndef DISABLE_PFR_SERIALIZATION_SELFCHECK + #include +#endif #define BEGIN_BOOST_SERIALIZATION() template void serialize(t_archive &_arch, const unsigned int ver) { template struct TAssertEquality { @@ -26,6 +29,60 @@ template struct TAssertEquality { #define END_BOOST_SERIALIZATION() } + +/********************************************************************************************************************************** + This serialization closing macro adds self-validation by checking the total number of fields in the structure using boost::pfr. + + Note: "num_fields" does NOT represent the number of fields included in the serialization. Instead, it indicates the total number + of fields in the structure, some of which might not be included in the serialization for valid reasons. If someone adds new + fields to the structure but forgets to update the serialization map, the compilation will fail. Any update to "num_fields" must + be accompanied by a thorough review of the serialization map to ensure no fields are omitted. +**********************************************************************************************************************************/ +#ifndef DISABLE_PFR_SERIALIZATION_SELFCHECK + #define END_BOOST_SERIALIZATION_TOTAL_FIELDS(num_fields) static_assert(num_fields == boost::pfr::tuple_size::type>::value, "Unexpected number of fields!"); } +#else + #define END_BOOST_SERIALIZATION_TOTAL_FIELDS(num_fields) END_BOOST_SERIALIZATION() +#endif + +#define BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(current_version) static const unsigned int current_boost_version_serialization_version = current_version; + +#define LOOP_BACK_BOOST_SERIALIZATION_VERSION(type) BOOST_CLASS_VERSION(type, type::current_boost_version_serialization_version); + + + +template +struct boost_transition_t {}; + +template +struct boost_transition_t +{ + template + static void chain_serialize(archive& ar, const origin_type& origin_tx) + { + destination_t dst_tx = AUTO_VAL_INIT(dst_tx); + transition_convert(origin_tx, dst_tx); + ar & dst_tx; + } +}; + +template +struct boost_transition_t +{ + template + static void chain_serialize(archive& ar, origin_type& origin_tx) + { + // TODO: consider using move semantic for temporary 'dst_tx' + destination_t dst_tx = AUTO_VAL_INIT(dst_tx); + ar & dst_tx; + transition_convert(dst_tx, origin_tx); + } +}; + + +#define BOOST_CHAIN_TRANSITION_VER(obj_version, old_type) if (obj_version == ver) {boost_transition_t::chain_serialize(_arch, *this);return;} + +#define BOOST_CHAIN_TRANSITION_IF_COND_TRUE(condition, old_type) if (condition) {boost_transition_t::chain_serialize(_arch, *this);return;} + /* example of use: diff --git a/src/common/crypto_serialization.h b/src/common/crypto_serialization.h index 481b3ff2..21845ae9 100644 --- a/src/common/crypto_serialization.h +++ b/src/common/crypto_serialization.h @@ -313,5 +313,18 @@ namespace boost { a & reinterpret_cast(x); } + template + inline void serialize(Archive& a, crypto::scalar_vec_t& x, const boost::serialization::version_type ver) + { + static_assert(sizeof(std::vector) == sizeof(crypto::scalar_vec_t)); + a & static_cast&>(x); + } + template + inline void serialize(Archive& a, crypto::scalar_mat_t& x, const boost::serialization::version_type ver) + { + static_assert(sizeof(std::vector) == sizeof(crypto::scalar_mat_t)); + a & static_cast&>(x); + } + } // namespace serialization } // namespace boost diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index 9dad0b4e..3a76fa59 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -1083,7 +1083,6 @@ namespace crypto make_random(); } - }; // scalar_vec_t diff --git a/src/crypto/eth_signature.cpp b/src/crypto/eth_signature.cpp index ba5b1358..c5e0999b 100644 --- a/src/crypto/eth_signature.cpp +++ b/src/crypto/eth_signature.cpp @@ -3,18 +3,245 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "eth_signature.h" #include "crypto.h" -#include "bitcoin-secp256k1/include/secp256k1.h" +#ifndef USE_OPEN_SSL_FOR_ECDSA + #include "bitcoin-secp256k1/include/secp256k1.h" +#endif #include "random.h" #include "misc_language.h" #include +#ifdef USE_OPEN_SSL_FOR_ECDSA + #include + #include + #include + #include + #include +#endif + + +// Function to create EC_KEY from raw 32 - byte private key +EC_KEY * create_ec_key_from_private_key(const unsigned char* private_key) { + EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!key) { + std::cerr << "Failed to create new EC Key" << std::endl; + return nullptr; + } + + BIGNUM* priv_key_bn = BN_bin2bn(private_key, 32, nullptr); + if (!priv_key_bn) { + std::cerr << "Failed to convert private key to BIGNUM" << std::endl; + EC_KEY_free(key); + return nullptr; + } + + if (!EC_KEY_set_private_key(key, priv_key_bn)) { + std::cerr << "Failed to set private key" << std::endl; + EC_KEY_free(key); + BN_free(priv_key_bn); + return nullptr; + } + + BN_free(priv_key_bn); + return key; +} + + +void ensure_canonical_s(BIGNUM* s, const EC_GROUP* group) { + // Get the order of the curve + BIGNUM* order = BN_new(); + EC_GROUP_get_order(group, order, nullptr); + + // Compute half of the order: `n / 2` + BIGNUM* half_order = BN_new(); + BN_rshift1(half_order, order); + + // If `s` is greater than `n / 2`, replace `s` with `n - s` + if (BN_cmp(s, half_order) > 0) { + BN_sub(s, order, s); + } + + BN_free(order); + BN_free(half_order); +} + +// Update the function to ensure canonical `s` +bool generate_ethereum_signature(const unsigned char* hash, const unsigned char* private_key, crypto::eth_signature& sig_res) { + EC_KEY* ec_key = create_ec_key_from_private_key(private_key); + if (!ec_key) { + throw std::runtime_error("Failed to create EC key from private key"); + } + + // Sign the hash + unsigned int sig_len = ECDSA_size(ec_key); + std::vector signature(sig_len); + if (ECDSA_sign(0, hash, 32, signature.data(), &sig_len, ec_key) == 0) { + EC_KEY_free(ec_key); + throw std::runtime_error("Failed to create signature"); + } + signature.resize(sig_len); + + + // The OpenSSL ECDSA signature output is DER encoded, Ethereum expects (r, s, v) + const unsigned char* p = signature.data(); + ECDSA_SIG* sig = d2i_ECDSA_SIG(nullptr, &p, sig_len); + if (!sig) { + EC_KEY_free(ec_key); + throw std::runtime_error("Failed to parse ECDSA signature"); + } + + const BIGNUM* r = nullptr; + const BIGNUM* s = nullptr; + ECDSA_SIG_get0(sig, &r, &s); + + // Ensure canonical `s` + BIGNUM* s_canonical = BN_dup(s); + ensure_canonical_s(s_canonical, EC_KEY_get0_group(ec_key)); + + BN_bn2binpad(r, (unsigned char* )&sig_res.data[0], 32); + BN_bn2binpad(s_canonical, (unsigned char*)&sig_res.data[32], 32); + + + ECDSA_SIG_free(sig); + BN_free(s_canonical); + EC_KEY_free(ec_key); + return true; +} + +// Convert raw 33-byte compressed public key to EC_KEY object +EC_KEY* create_ec_key_from_compressed_public_key(const unsigned char* compressed_pub_key) { + EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!key) { + std::cerr << "Failed to create EC_KEY object" << std::endl; + return nullptr; + } + + EC_POINT* pub_point = EC_POINT_new(EC_KEY_get0_group(key)); + if (!EC_POINT_oct2point(EC_KEY_get0_group(key), pub_point, compressed_pub_key, 33, nullptr)) { + std::cerr << "Failed to convert compressed public key" << std::endl; + EC_POINT_free(pub_point); + EC_KEY_free(key); + return nullptr; + } + + if (!EC_KEY_set_public_key(key, pub_point)) { + std::cerr << "Failed to set public key" << std::endl; + EC_POINT_free(pub_point); + EC_KEY_free(key); + return nullptr; + } + + EC_POINT_free(pub_point); + return key; +} + +// Function to verify Ethereum-compatible signature +bool verify_ethereum_signature(const crypto::hash& m, const crypto::eth_signature& sig_res, const crypto::eth_public_key& compressed_pub_key) { + EC_KEY* ec_key = create_ec_key_from_compressed_public_key((const unsigned char*)&compressed_pub_key.data[0]); + if (!ec_key) { + throw std::runtime_error("Failed to create EC key from compressed public key"); + } + const unsigned char* r = (unsigned char*)&sig_res.data[0]; + const unsigned char* s = (unsigned char*)&sig_res.data[32]; + const unsigned char* hash = (unsigned char*)&m; + + // Create ECDSA_SIG from r and s + BIGNUM* bn_r = BN_bin2bn(r, 32, nullptr); + BIGNUM* bn_s = BN_bin2bn(s, 32, nullptr); + if (!bn_r || !bn_s) { + EC_KEY_free(ec_key); + BN_free(bn_r); + BN_free(bn_s); + throw std::runtime_error("Failed to convert r or s to BIGNUM"); + } + + ECDSA_SIG* sig = ECDSA_SIG_new(); + if (!sig) { + EC_KEY_free(ec_key); + BN_free(bn_r); + BN_free(bn_s); + throw std::runtime_error("Failed to create ECDSA_SIG object"); + } + + if (!ECDSA_SIG_set0(sig, bn_r, bn_s)) { + EC_KEY_free(ec_key); + ECDSA_SIG_free(sig); + BN_free(bn_r); + BN_free(bn_s); + throw std::runtime_error("Failed to set r and s in ECDSA_SIG"); + } + + // Verify the signature + int verification_result = ECDSA_do_verify(hash, 32, sig, ec_key); + + ECDSA_SIG_free(sig); + EC_KEY_free(ec_key); + + + return verification_result == 1; +} + + +// +// struct KeyPair { +// std::vector private_key; // 32 bytes +// std::vector public_key; // 33 bytes (compressed format) +// }; + +// Function to generate an Ethereum-compatible key pair +bool generate_ethereum_key_pair(crypto::eth_secret_key& sec_key, crypto::eth_public_key& pub_key) { + /*KeyPair keypair;*/ + + // Create a new EC_KEY object with the secp256k1 curve + EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1); + if (!key) { + throw std::runtime_error("Failed to create new EC_KEY object"); + } + + // Generate the key pair + if (EC_KEY_generate_key(key) == 0) { + EC_KEY_free(key); + throw std::runtime_error("Failed to generate key pair"); + } + + // Extract the private key + const BIGNUM* priv_bn = EC_KEY_get0_private_key(key); + if (!priv_bn) { + EC_KEY_free(key); + throw std::runtime_error("Failed to get private key"); + } + + BN_bn2binpad(priv_bn, (unsigned char*)&sec_key.data[0], 32); + + // Extract the public key in compressed format + const EC_POINT* pub_point = EC_KEY_get0_public_key(key); + if (!pub_point) { + EC_KEY_free(key); + throw std::runtime_error("Failed to get public key"); + } + + //keypair.public_key.resize(33); // Compressed format + if (EC_POINT_point2oct(EC_KEY_get0_group(key), pub_point, POINT_CONVERSION_COMPRESSED, + (unsigned char*)&pub_key.data[0], sizeof(pub_key.data), nullptr) == 0) { + EC_KEY_free(key); + throw std::runtime_error("Failed to convert public key to compressed format"); + } + + EC_KEY_free(key); + return true; +} + + + + + namespace crypto { bool generate_eth_key_pair(eth_secret_key& sec_key, eth_public_key& pub_key) noexcept { try { +#ifndef USE_OPEN_SSL_FOR_ECDSA secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){ secp256k1_context_destroy(ctx); @@ -44,6 +271,9 @@ namespace crypto return false; return true; +#else + return generate_ethereum_key_pair(sec_key, pub_key); +#endif } catch(...) { @@ -51,6 +281,7 @@ namespace crypto } } +#ifndef USE_OPEN_SSL_FOR_ECDSA bool eth_secret_key_to_public_key(const eth_secret_key& sec_key, eth_public_key& pub_key) noexcept { try @@ -77,12 +308,13 @@ namespace crypto return false; } } - +#endif // generates secp256k1 ECDSA signature bool generate_eth_signature(const hash& m, const eth_secret_key& sec_key, eth_signature& sig) noexcept { try { +#ifndef USE_OPEN_SSL_FOR_ECDSA secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){ secp256k1_context_destroy(ctx); @@ -102,6 +334,9 @@ namespace crypto return false; return true; +#else + return generate_ethereum_signature((const unsigned char*)&m.data, (unsigned char*)&sec_key.data, sig); +#endif } catch(...) { @@ -115,7 +350,7 @@ namespace crypto try { // TODO (performance) consider using secp256k1_context_static for verification -- sowle - +#ifndef USE_OPEN_SSL_FOR_ECDSA secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE); auto slh = epee::misc_utils::create_scope_leave_handler([&ctx](){ secp256k1_context_destroy(ctx); @@ -141,6 +376,9 @@ namespace crypto return false; return true; +#else + return verify_ethereum_signature(m, sig, pub_key); +#endif } catch(...) { diff --git a/src/crypto/eth_signature.h b/src/crypto/eth_signature.h index b12d41fe..4db0b8e7 100644 --- a/src/crypto/eth_signature.h +++ b/src/crypto/eth_signature.h @@ -31,7 +31,7 @@ namespace crypto bool generate_eth_key_pair(eth_secret_key& sec_key, eth_public_key& pub_key) noexcept; // converts eth_secret_key to eth_public_key - bool eth_secret_key_to_public_key(const eth_secret_key& sec_key, eth_public_key& pub_key) noexcept; + //bool _eth_secret_key_to_public_key(const eth_secret_key& sec_key, eth_public_key& pub_key) noexcept; // generates secp256k1 ECDSA signature bool generate_eth_signature(const hash& m, const eth_secret_key& sec_key, eth_signature& sig) noexcept; diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index f5663826..ff194a59 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -86,6 +86,7 @@ namespace currency std::vector processed_seed_binary = keys_seed_binary; if (!password.empty()) { + CHECK_AND_ASSERT_THROW_MES(currency::validate_password(password), "seed phrase password contains invalid characters, seed phrase cannot be created with such a password"); //encrypt seed phrase binary data crypt_with_pass(&keys_seed_binary[0], keys_seed_binary.size(), &processed_seed_binary[0], password); } @@ -107,6 +108,9 @@ namespace currency uint64_t h_64 = *reinterpret_cast(&h); uint16_t checksum = h_64 % (checksum_max + 1); + if (checksum == checksum_max) // workaround for incorrect checksum calculation (trying to keep the whole scheme untouched) -- sowle + checksum = 0; + uint8_t auditable_flag = 0; if (m_keys.account_address.flags & ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE) auditable_flag = 1; @@ -215,6 +219,10 @@ namespace currency h = crypto::cn_fast_hash(&h, sizeof h); uint64_t h_64 = *reinterpret_cast(&h); uint16_t checksum_calculated = h_64 % (checksum_max + 1); + + if (checksum_calculated == checksum_max) // workaround for incorrect checksum calculation (trying to keep the whole scheme untouched) -- sowle + checksum_calculated = 0; + if (checksum != checksum_calculated) { LOG_PRINT_L0("seed phase has invalid checksum: " << checksum_calculated << ", while " << checksum << " is expected, check your words"); @@ -229,6 +237,8 @@ namespace currency if (auditable_flag) m_keys.account_address.flags |= ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE; + else + m_keys.account_address.flags &= ~ACCOUNT_PUBLIC_ADDRESS_FLAG_AUDITABLE; return true; } diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 6d4cbc1f..0d6d41f8 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -830,7 +830,7 @@ bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& t fee = get_tx_fee(tx_res_ptr->tx); purge_transaction_keyimages_from_blockchain(tx, true); - bool r = unprocess_blockchain_tx_extra(tx); + bool r = unprocess_blockchain_tx_extra(tx, tx_res_ptr->m_keeper_block_height); CHECK_AND_ASSERT_MES(r, false, "failed to unprocess_blockchain_tx_extra for tx " << tx_id); r = unprocess_blockchain_tx_attachments(tx, get_current_blockchain_size(), 0/*TODO: add valid timestamp here in future if need*/); @@ -1553,8 +1553,20 @@ bool blockchain_storage::create_block_template(const create_block_template_param } diffic = get_next_diff_conditional(pos); + CHECK_AND_ASSERT_MES(diffic, false, "get_next_diff_conditional failed"); + + // check PoW block timestamp against the current blockchain timestamp median -- if it's not okay, don't create a new block + // TODO (performance) both get_next_diff_conditional and get_last_n_blocks_timestamps obtains last N blocks, consider data reusing -- sowle + if (!pos && !params.ignore_pow_ts_check) + { + uint64_t median_ts = get_last_n_blocks_timestamps_median(BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW); + if(b.timestamp < median_ts) + { + LOG_PRINT_YELLOW("Block template construction failed because current core timestamp, " << b.timestamp << ", is less than median of last " << BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW << " blocks, " << median_ts, LOG_LEVEL_2); + return false; + } + } - CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead."); @@ -3805,7 +3817,7 @@ bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx return true; } //------------------------------------------------------------------ -bool blockchain_storage::unprocess_blockchain_tx_extra(const transaction& tx) +bool blockchain_storage::unprocess_blockchain_tx_extra(const transaction& tx, const uint64_t height) { tx_extra_info ei = AUTO_VAL_INIT(ei); bool r = parse_and_validate_tx_extra(tx, ei); @@ -3818,9 +3830,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; - 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); + r = pop_asset_info(ei.m_asset_operation, height); CHECK_AND_ASSERT_MES(r, false, "failed to pop_alias_info"); } return true; @@ -3862,15 +3872,16 @@ bool blockchain_storage::get_asset_info(const crypto::public_key& asset_id, asse { CRITICAL_REGION_LOCAL(m_read_lock); auto as_ptr = m_db_assets.find(asset_id); - if (as_ptr) - { - if (as_ptr->size()) - { - result = as_ptr->back().descriptor; - return true; - } - } - return false; + if (!as_ptr) + return false; + if (as_ptr->empty()) + return false; + // the last history item must have opt_descriptor, but we check it just to be sure + if (!as_ptr->back().opt_descriptor.has_value()) + return false; + + result = as_ptr->back().opt_descriptor.get(); + return true; } //------------------------------------------------------------------ uint64_t blockchain_storage::get_assets(uint64_t offset, uint64_t count, std::list& assets) const @@ -3882,15 +3893,19 @@ uint64_t blockchain_storage::get_assets(uint64_t offset, uint64_t count, std::li if (i < offset) return true; // continue - CHECK_AND_ASSERT_THROW_MES(asset_descriptor_history.size(), "asset_descriptor_history unexpectedly have 0 size, asset_id: " << asset_id); - assets.push_back(asset_descriptor_with_id()); - static_cast(assets.back()) = asset_descriptor_history.back().descriptor; - assets.back().asset_id = asset_id; + CHECK_AND_ASSERT_THROW_MES(asset_descriptor_history.size(), "unexpectedly, the asset_descriptor_history is empty; asset_id: " << asset_id); + CHECK_AND_ASSERT_THROW_MES(asset_descriptor_history.back().opt_descriptor.has_value(), "the last element of asset_descriptor_history doesn't have descriptor; asset_id: " << asset_id); + asset_descriptor_with_id& added_item = assets.emplace_back(); + asset_descriptor_base& added_item_adb = static_cast(added_item); + added_item_adb = asset_descriptor_history.back().opt_descriptor.get(); + replace_asset_ticker_and_full_name_if_invalid(added_item_adb, asset_id); + added_item.asset_id = asset_id; + if (assets.size() >= count) { - return false; + return false; // stop } - return true; + return true; // continue }); return assets.size(); } @@ -4084,21 +4099,79 @@ bool blockchain_storage::put_alias_info(const transaction & tx, extra_alias_entr return true; } //------------------------------------------------------------------ -bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id) +bool blockchain_storage::pop_asset_info(const asset_descriptor_operation& ado, const uint64_t height) { CRITICAL_REGION_LOCAL(m_read_lock); + crypto::public_key asset_id = currency::null_pkey; + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, nullptr, &asset_id), false, "get_or_calculate_asset_id failed"); + auto asset_history_ptr = m_db_assets.find(asset_id); CHECK_AND_ASSERT_MES(asset_history_ptr && asset_history_ptr->size(), false, "empty name list in pop_asset_info"); - + assets_container::t_value_type local_asset_hist = *asset_history_ptr; - local_asset_hist.pop_back(); + + if (is_hardfork_active_for_height(ZANO_HARDFORK_05, height)) + { + // NEW HF5 handling + assets_container::t_value_type local_asset_hist = *asset_history_ptr; + asset_descriptor_operation& last_ado = local_asset_hist.back(); // above we made sure that the history isn't empty + CHECK_AND_ASSERT_MES(last_ado.opt_descriptor.has_value(), false, "opt_descriptor is missing during asset pop, op: " << (int)ado.operation_type); + asset_descriptor_base& last_adb = last_ado.opt_descriptor.get(); + + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) + { + // just change the most recent history record, don't pop + if (last_adb.hidden_supply) + { + //CHECK_AND_ASSERT_MES(last_ado.opt_amount_commitment.has_value() && ado.opt_amount_commitment.has_value(), false, "last_ado.opt_amount_commitment or ado.opt_amount_commitment is missing (emit)"); + //last_ado.opt_amount_commitment.get() = (crypto::point_t(last_ado.opt_amount_commitment.get()) - crypto::point_t(ado.opt_amount_commitment.get())).to_public_key(); + return false; // not supported atm + } + else + { + CHECK_AND_ASSERT_MES(ado.opt_amount.has_value(), false, "last_ado.opt_amount or ado.opt_amount is missing (emit)"); + last_adb.current_supply -= ado.opt_amount.get(); + } + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + // just change the most recent history record, don't pop + if (last_adb.hidden_supply) + { + //CHECK_AND_ASSERT_MES(last_ado.opt_amount_commitment.has_value() && ado.opt_amount_commitment.has_value(), false, "last_ado.opt_amount_commitment or ado.opt_amount_commitment is missing (burn)"); + //last_ado.opt_amount_commitment.get() = (crypto::point_t(last_ado.opt_amount_commitment.get()) + crypto::point_t(ado.opt_amount_commitment.get())).to_public_key(); + return false; // not supported atm + } + else + { + CHECK_AND_ASSERT_MES(ado.opt_amount.has_value(), false, "last_ado.opt_amount or ado.opt_amount is missing (burn)"); + last_adb.current_supply += ado.opt_amount.get(); + } + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + // just pop the most recent history record + local_asset_hist.pop_back(); + } + else + { + CHECK_AND_ASSERT_MES(false, false, "invalid operation: " << (int)ado.operation_type); + } + } + else + { + // HF4 + local_asset_hist.pop_back(); + } + + // both HF4 and HF5 if (local_asset_hist.size()) m_db_assets.set(asset_id, local_asset_hist); else m_db_assets.erase(asset_id); - LOG_PRINT_MAGENTA("[ASSET_POP]: " << asset_id << ": " << (!local_asset_hist.empty() ? "(prev)" : "(erased)"), LOG_LEVEL_1); + return true; } //------------------------------------------------------------------ @@ -4107,16 +4180,18 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a bool r = false; CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has empty history record"); const asset_descriptor_operation& last_ado = avc.asset_op_history->back(); + CHECK_AND_ASSERT_MES(last_ado.opt_descriptor.has_value(), false, "last ado is missing opt_descriptor; asset id: " << avc.asset_id); + const asset_descriptor_base& last_adb = last_ado.opt_descriptor.get(); - if (is_hardfork_active(ZANO_HARDFORK_05)) // TODO: consider changing to height-specific check + if (is_hardfork_active_for_height(ZANO_HARDFORK_05, avc.height)) { - if (last_ado.descriptor.owner_eth_pub_key.has_value()) + if (last_adb.owner_eth_pub_key.has_value()) { - CHECK_AND_ASSERT_MES(last_ado.descriptor.owner == null_pkey, false, "owner_eth_pub_key is set but owner pubkey is nonzero"); + CHECK_AND_ASSERT_MES(last_adb.owner == null_pkey, false, "owner_eth_pub_key is set but owner pubkey is nonzero"); asset_operation_ownership_proof_eth aoop_eth{}; r = get_type_in_variant_container(avc.tx.proofs, aoop_eth); CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed: asset_operation_ownership_proof_eth is missing"); - if (!crypto::verify_eth_signature(avc.tx_id, last_ado.descriptor.owner_eth_pub_key.value(), aoop_eth.eth_sig)) + if (!crypto::verify_eth_signature(avc.tx_id, last_adb.owner_eth_pub_key.value(), aoop_eth.eth_sig)) { LOG_ERROR("Failed to validate secp256k1 signature for hash: " << avc.tx_id << ", signature: " << aoop_eth.eth_sig); return false; @@ -4133,12 +4208,13 @@ bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& a r = get_type_in_variant_container(avc.tx.proofs, aoop); CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed: asset_operation_ownership_proof is missing"); - return crypto::verify_schnorr_sig(avc.tx_id, last_ado.descriptor.owner, aoop.gss); + return crypto::verify_schnorr_sig(avc.tx_id, last_adb.owner, aoop.gss); } //------------------------------------------------------------------ -bool blockchain_storage::validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const +bool blockchain_storage::validate_asset_operation_hf4(asset_op_verification_context& avc) const { CRITICAL_REGION_LOCAL(m_read_lock); + CHECK_AND_ASSERT_MES(!is_hardfork_active_for_height(ZANO_HARDFORK_05, avc.height), false, "validate_asset_operation_hf4 was called in HF5"); 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); @@ -4150,16 +4226,25 @@ bool blockchain_storage::validate_asset_operation_against_current_blochain_state if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) { 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; - if(this->is_hardfork_active(ZANO_HARDFORK_05)) - { - CHECK_AND_ASSERT_MES(validate_ado_initial(ado.descriptor), false, "validate_ado_initial failed!"); - } + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing while registering asset " << avc.asset_id); + + // CZ please review the following two added lines, do we need them _here_? I think they should go to hardfork_specific_terms... + // anyway, we musn't miss these checks for the sake of consensus + CHECK_AND_ASSERT_MES(!ado.opt_descriptor.get().owner_eth_pub_key.has_value(), false, "owner_eth_pub_key is prohibited before HF5"); + CHECK_AND_ASSERT_MES(!ado.opt_asset_id_salt.has_value(), false, "opt_asset_id_salt is prohibited before HF5"); + + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing while registering asset " << avc.asset_id); + avc.amount_to_validate = ado.opt_descriptor.get().current_supply; } else { CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size() > 0, false, "asset with id " << avc.asset_id << " has not been registered"); const asset_descriptor_operation& last_ado = avc.asset_op_history->back(); + CHECK_AND_ASSERT_MES(last_ado.opt_descriptor.has_value(), false, "opt_descriptor is missing in last ado, op: " << (int)ado.operation_type); + const asset_descriptor_base& last_adb = last_ado.opt_descriptor.get(); + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing in ado, op: " << (int)ado.operation_type); + const asset_descriptor_base adb = ado.opt_descriptor.get(); + // check ownership permission if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) { @@ -4171,23 +4256,23 @@ bool blockchain_storage::validate_asset_operation_against_current_blochain_state if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) { //check that total current_supply haven't changed - CHECK_AND_ASSERT_MES(ado.descriptor.current_supply == last_ado.descriptor.current_supply, false, "update operation attempted to change emission, failed"); - CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_ado.descriptor), false, "update operation modifies asset descriptor in a prohibited manner"); + CHECK_AND_ASSERT_MES(adb.current_supply == last_adb.current_supply, false, "update operation attempted to change emission, failed"); + CHECK_AND_ASSERT_MES(validate_ado_update_allowed(adb, last_adb), false, "update operation modifies asset descriptor in a prohibited manner"); need_to_validate_ao_amount_commitment = false; } else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) { - CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > last_ado.descriptor.current_supply, false, "emit operation does not increase the current supply, failed"); - CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_ado.descriptor), false, "emit operation modifies asset descriptor in a prohibited manner"); - CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == last_ado.descriptor.meta_info, false, "emit operation is not allowed to update meta info"); - avc.amount_to_validate = ado.descriptor.current_supply - last_ado.descriptor.current_supply; + CHECK_AND_ASSERT_MES(adb.current_supply > last_adb.current_supply, false, "emit operation does not increase the current supply, failed"); + CHECK_AND_ASSERT_MES(validate_ado_update_allowed(adb, last_adb), false, "emit operation modifies asset descriptor in a prohibited manner"); + CHECK_AND_ASSERT_MES(adb.meta_info == last_adb.meta_info, false, "emit operation is not allowed to update meta info"); + avc.amount_to_validate = adb.current_supply - last_adb.current_supply; } else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) { - CHECK_AND_ASSERT_MES(ado.descriptor.current_supply < last_ado.descriptor.current_supply, false, "burn operation does not decrease the current supply, failed"); - CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_ado.descriptor), false, "burn operation modifies asset descriptor in a prohibited manner"); - CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == last_ado.descriptor.meta_info, false, "burn operation is not allowed to update meta info"); - avc.amount_to_validate = last_ado.descriptor.current_supply - ado.descriptor.current_supply; + CHECK_AND_ASSERT_MES(adb.current_supply < last_adb.current_supply, false, "burn operation does not decrease the current supply, failed"); + CHECK_AND_ASSERT_MES(validate_ado_update_allowed(adb, last_adb), false, "burn operation modifies asset descriptor in a prohibited manner"); + CHECK_AND_ASSERT_MES(adb.meta_info == last_adb.meta_info, false, "burn operation is not allowed to update meta info"); + avc.amount_to_validate = last_adb.current_supply - adb.current_supply; } else { @@ -4205,35 +4290,208 @@ bool blockchain_storage::validate_asset_operation_against_current_blochain_state return true; } //------------------------------------------------------------------ -bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) +bool blockchain_storage::validate_asset_operation_hf5(asset_op_verification_context& avc) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + CHECK_AND_ASSERT_MES(is_hardfork_active_for_height(ZANO_HARDFORK_05, avc.height), false, "validate_asset_operation was called before HF5"); + + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); + avc.asset_op_history = m_db_assets.find(avc.asset_id); + + const asset_descriptor_operation& ado = avc.ado; + + bool need_to_validate_ao_amount_commitment = true; + + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) + { + CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << avc.asset_id << " has already been registered"); + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing while registering asset " << avc.asset_id); + avc.amount_to_validate = ado.opt_descriptor.get().current_supply; + // HF5 specific + CHECK_AND_ASSERT_MES(validate_ado_initial(ado.opt_descriptor.get()), false, "validate_ado_initial failed!"); + CHECK_AND_ASSERT_MES(ado.opt_amount.has_value() && avc.amount_to_validate == ado.opt_amount.get(), false, "opt_amount is missing or incorrect"); + } + else + { + CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size() > 0, false, "asset with id " << avc.asset_id << " has not been registered"); + const asset_descriptor_operation& last_ado = avc.asset_op_history->back(); + CHECK_AND_ASSERT_MES(last_ado.opt_descriptor.has_value(), false, "opt_descriptor is missing in last ado, op: " << (int)ado.operation_type); + const asset_descriptor_base& last_adb = last_ado.opt_descriptor.get(); + + // check ownership permission + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + bool r = validate_ado_ownership(avc); + CHECK_AND_ASSERT_MES(r, false, "Failed to validate ownership of asset_descriptor_operation, rejecting"); + } + + avc.amount_to_validate = 0; + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing (update)"); + //check that total current_supply haven't changed + CHECK_AND_ASSERT_MES(ado.opt_descriptor.get().current_supply == last_adb.current_supply, false, "update operation attempted to change emission, failed"); + CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.opt_descriptor.get(), last_adb), false, "update operation modifies asset descriptor in a prohibited manner"); + need_to_validate_ao_amount_commitment = false; + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) + { + //CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > last_adb.current_supply, false, "emit operation does not increase the current supply, failed"); + //CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_adb), false, "emit operation modifies asset descriptor in a prohibited manner"); + //CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == last_adb.meta_info, false, "emit operation is not allowed to update meta info"); + + if (!last_adb.hidden_supply) + { + CHECK_AND_ASSERT_MES(ado.opt_amount.has_value(), false, "opt_amount is missing (emit)"); + uint64_t amount = ado.opt_amount.get(); + + CHECK_AND_ASSERT_MES(last_adb.current_supply + amount >= last_adb.current_supply, false, "current_supply overflow: " << last_adb.current_supply << ", amount: " << amount << " (emit)"); + CHECK_AND_ASSERT_MES(last_adb.current_supply + amount <= last_adb.total_max_supply, false, "current_supply overflow: " << last_adb.current_supply << ", amount: " << amount << ", max supply: " << last_adb.total_max_supply << " (emit)"); + avc.amount_to_validate = amount; + } + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + //CHECK_AND_ASSERT_MES(ado.descriptor.current_supply < last_adb.current_supply, false, "burn operation does not decrease the current supply, failed"); + //CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, last_adb), false, "burn operation modifies asset descriptor in a prohibited manner"); + //CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == last_adb.meta_info, false, "burn operation is not allowed to update meta info"); + + if (!last_adb.hidden_supply) + { + CHECK_AND_ASSERT_MES(ado.opt_amount.has_value(), false, "opt_amount is missing (burn)"); + uint64_t amount = ado.opt_amount.get(); + + CHECK_AND_ASSERT_MES(last_adb.current_supply - amount <= last_adb.current_supply, false, "current_supply overflow: " << last_adb.current_supply << ", amount: " << amount << " (burn)"); + avc.amount_to_validate = amount; + } + } + else + { + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); + return false; + } + } + + if (need_to_validate_ao_amount_commitment) + { + bool r = validate_asset_operation_amount_commitment(avc); + CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation"); + } + + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_asset_operation(asset_op_verification_context& avc, uint64_t height) const +{ + if (is_hardfork_active_for_height(ZANO_HARDFORK_05, height)) + { + return validate_asset_operation_hf5(avc); + } + else + { + return validate_asset_operation_hf4(avc); + } +} +//------------------------------------------------------------------ +bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado, const uint64_t height) { CRITICAL_REGION_LOCAL(m_read_lock); - asset_op_verification_context avc = { tx, tx_id, ado }; - CHECK_AND_ASSERT_MES(validate_asset_operation_against_current_blochain_state(avc), false, "asset operation validation failed"); + asset_op_verification_context avc = { tx, tx_id, ado, height }; + CHECK_AND_ASSERT_MES(validate_asset_operation(avc, height), false, "asset operation validation failed"); - assets_container::t_value_type local_asset_history{}; - if (avc.asset_op_history) - local_asset_history = *avc.asset_op_history; - local_asset_history.push_back(ado); - m_db_assets.set(avc.asset_id, local_asset_history); - - switch(ado.operation_type) + if (is_hardfork_active_for_height(ZANO_HARDFORK_05, height)) { - case ASSET_DESCRIPTOR_OPERATION_REGISTER: - LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - case ASSET_DESCRIPTOR_OPERATION_UPDATE: - LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - case ASSET_DESCRIPTOR_OPERATION_EMIT: - LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: - LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); - break; - default: - LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); + // NEW HF5 handling here + + assets_container::t_value_type local_asset_history{}; + if (avc.asset_op_history) + local_asset_history = *avc.asset_op_history; + + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) + { + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing (register)"); // validated in validate_asset_operation(), just in case + const asset_descriptor_base& adb = ado.opt_descriptor.get(); + local_asset_history.push_back(ado); + LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(adb.current_supply, adb.decimal_point) << ", " << avc.asset_id << ": " << adb.ticker << ", \"" << adb.full_name << "\"", LOG_LEVEL_1); + } + else + { + CHECK_AND_ASSERT_MES(!local_asset_history.empty(), false, "local_asset_history is empty (update/emit/burn)"); + asset_descriptor_operation& last_ado = local_asset_history.back(); + CHECK_AND_ASSERT_MES(last_ado.opt_descriptor.has_value(), false, "last_ado.opt_descriptor is missing (update/emit/burn)"); + asset_descriptor_base& last_adb = local_asset_history.back().opt_descriptor.get(); + + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + local_asset_history.push_back(ado); + LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << last_adb.ticker << ", \"" << last_adb.full_name << "\"", LOG_LEVEL_1); + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) + { + // just change the most recent history record, don't push + if (last_adb.hidden_supply) + { + //CHECK_AND_ASSERT_MES(last_ado.opt_amount_commitment.has_value() && ado.opt_amount_commitment.has_value(), false, "last_ado.opt_amount_commitment or ado.opt_amount_commitment is missing (emit)"); + //last_ado.opt_amount_commitment.get() = (crypto::point_t(last_ado.opt_amount_commitment.get()) + crypto::point_t(ado.opt_amount_commitment.get())).to_public_key(); + return false; // not supported atm + } + else + { + CHECK_AND_ASSERT_MES(ado.opt_amount.has_value(), false, "last_ado.opt_amount or ado.opt_amount is missing (emit)"); + last_adb.current_supply += ado.opt_amount.get(); + } + LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, last_adb.decimal_point) << ", " << avc.asset_id << ": " << last_adb.ticker << ", \"" << last_adb.full_name << "\"", LOG_LEVEL_1); + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + // just change the most recent history record, don't push + if (last_adb.hidden_supply) + { + //CHECK_AND_ASSERT_MES(last_ado.opt_amount_commitment.has_value() && ado.opt_amount_commitment.has_value(), false, "last_ado.opt_amount_commitment or ado.opt_amount_commitment is missing (burn)"); + //last_ado.opt_amount_commitment.get() = (crypto::point_t(last_ado.opt_amount_commitment.get()) - crypto::point_t(ado.opt_amount_commitment.get())).to_public_key(); + return false; // not supported atm + } + else + { + CHECK_AND_ASSERT_MES(ado.opt_amount.has_value(), false, "last_ado.opt_amount or ado.opt_amount is missing (burn)"); + last_adb.current_supply -= ado.opt_amount.get(); + } + LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, last_adb.decimal_point) << ", " << avc.asset_id << ": " << last_adb.ticker << ", \"" << last_adb.full_name << "\"", LOG_LEVEL_1); + } + else + CHECK_AND_ASSERT_MES(false, false, "Unknown operation type: " << (int)ado.operation_type); + } + + m_db_assets.set(avc.asset_id, local_asset_history); + } + else + { + // HF4 + assets_container::t_value_type local_asset_history{}; + if (avc.asset_op_history) + local_asset_history = *avc.asset_op_history; + local_asset_history.push_back(ado); + m_db_assets.set(avc.asset_id, local_asset_history); + + const asset_descriptor_base& adb = ado.opt_descriptor.get(); // in HF4 descriptor must always be present, validated in validate_asset_operation_hf4() + switch(ado.operation_type) + { + case ASSET_DESCRIPTOR_OPERATION_REGISTER: + LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(adb.current_supply, adb.decimal_point) << ", " << avc.asset_id << ": " << adb.ticker << ", \"" << adb.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_UPDATE: + LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << adb.ticker << ", \"" << adb.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_EMIT: + LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, adb.decimal_point) << ", " << avc.asset_id << ": " << adb.ticker << ", \"" << adb.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: + LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, adb.decimal_point) << ", " << avc.asset_id << ": " << adb.ticker << ", \"" << adb.full_name << "\"", LOG_LEVEL_1); + break; + default: + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); + } } return true; @@ -4309,7 +4567,7 @@ bool blockchain_storage::prevalidate_alias_info(const transaction& tx, const ext return true; } //------------------------------------------------------------------ -bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id) +bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id, const uint64_t height) { //check transaction extra tx_extra_info ei = AUTO_VAL_INIT(ei); @@ -4325,7 +4583,7 @@ bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx, cons } if (ei.m_asset_operation.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED) { - r = put_asset_info(tx, tx_id, ei.m_asset_operation); + r = put_asset_info(tx, tx_id, ei.m_asset_operation, height); CHECK_AND_ASSERT_MES(r, false, "failed to put_asset_info"); } @@ -4525,7 +4783,7 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(tx, tx_id, bl_height), false, "tx " << tx_id << ": hardfork-specific validation failed"); TIME_MEASURE_START_PD(tx_process_extra); - bool r = process_blockchain_tx_extra(tx, tx_id); + bool r = process_blockchain_tx_extra(tx, tx_id, bl_height); CHECK_AND_ASSERT_MES(r, false, "failed to process_blockchain_tx_extra"); TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_extra); @@ -4541,7 +4799,7 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const { LOG_ERROR("critical internal error: add_transaction_input_visitor failed. but key_images should be already checked"); purge_transaction_keyimages_from_blockchain(tx, false); - bool r = unprocess_blockchain_tx_extra(tx); + bool r = unprocess_blockchain_tx_extra(tx, bl_height); CHECK_AND_ASSERT_MES(r, false, "failed to unprocess_blockchain_tx_extra"); unprocess_blockchain_tx_attachments(tx, bl_height, timestamp); @@ -4562,7 +4820,7 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const { LOG_ERROR("critical internal error: tx with id: " << tx_id << " in block id: " << bl_id << " already in blockchain"); purge_transaction_keyimages_from_blockchain(tx, true); - bool r = unprocess_blockchain_tx_extra(tx); + bool r = unprocess_blockchain_tx_extra(tx, bl_height); CHECK_AND_ASSERT_MES(r, false, "failed to unprocess_blockchain_tx_extra"); unprocess_blockchain_tx_attachments(tx, bl_height, timestamp); @@ -5451,7 +5709,8 @@ uint64_t blockchain_storage::get_last_n_blocks_timestamps_median(size_t n) const std::vector timestamps = get_last_n_blocks_timestamps(n); uint64_t median_res = epee::misc_utils::median(timestamps); - m_timestamps_median_cache[n] = median_res; + if (timestamps.size() == n) + m_timestamps_median_cache[n] = median_res; return median_res; } //------------------------------------------------------------------ @@ -6967,7 +7226,7 @@ bool blockchain_storage::is_hardfork_active(size_t hardfork_id) const //------------------------------------------------------------------ bool blockchain_storage::is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const { - return m_core_runtime_config.is_hardfork_active_for_height(hardfork_id, height); + return m_core_runtime_config.is_hardfork_active_for_height(hardfork_id, height != UINT64_MAX ? height : m_db_blocks.size()); } //------------------------------------------------------------------ bool blockchain_storage::prevalidate_block(const block& bl) diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 9d7cba3a..78c75e66 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -381,7 +381,9 @@ namespace currency const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0)const; bool validate_ado_ownership(asset_op_verification_context& avc) const; - bool validate_asset_operation_against_current_blochain_state(asset_op_verification_context& avc) const; + bool validate_asset_operation_hf4(asset_op_verification_context& avc) const; + bool validate_asset_operation_hf5(asset_op_verification_context& avc) const; + bool validate_asset_operation(asset_op_verification_context& avc, uint64_t height) const; void set_core_runtime_config(const core_runtime_config& pc) const; const core_runtime_config& get_core_runtime_config()const; @@ -679,14 +681,14 @@ namespace currency uint64_t get_adjusted_time()const; bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); bool update_next_comulative_size_limit(); - bool process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id); - bool unprocess_blockchain_tx_extra(const transaction& tx); + bool process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id, const uint64_t height); + bool unprocess_blockchain_tx_extra(const transaction& tx, const uint64_t height); bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp); bool unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp); bool pop_alias_info(const extra_alias_entry& ai); bool put_alias_info(const transaction& tx, extra_alias_entry& ai); - bool pop_asset_info(const crypto::public_key& asset_id); - bool put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado); + bool pop_asset_info(const asset_descriptor_operation& ado, const uint64_t height); + bool put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado, const uint64_t height); void fill_addr_to_alias_dict(); //bool resync_spent_tx_flags(); bool prune_ring_signatures_and_attachments_if_need(); diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h index 0013dc51..c15cdbe9 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -136,6 +136,7 @@ namespace currency account_public_address stakeholder_address; blobdata ex_nonce; bool pos = false; + bool ignore_pow_ts_check = false; pos_entry pe; std::list explicit_txs; fill_block_template_func_t *pcustom_fill_block_template_func; diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index c6581611..d0630089 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -74,7 +74,9 @@ namespace currency /************************************************************************/ /* */ /************************************************************************/ - + + struct asset_descriptor_operation_v1; + //since structure used in blockchain as a key accessor, then be sure that there is no padding inside #pragma pack(push, 1) struct account_public_address_old @@ -696,8 +698,20 @@ namespace currency } }; -#define ASSET_DESCRIPTOR_BASE_STRUCTURE_VER 1 +#define ASSET_DESCRIPTOR_BASE_HF4_VER 0 +#define ASSET_DESCRIPTOR_BASE_HF5_VER 2 +#define ASSET_DESCRIPTOR_BASE_LAST_VER 2 + struct dummy + { + BEGIN_SERIALIZE() + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + END_BOOST_SERIALIZATION_TOTAL_FIELDS(0) + }; + + typedef boost::variant asset_descriptor_base_etc_fields; typedef boost::variant asset_owner_pub_key_v; struct asset_descriptor_base @@ -710,11 +724,14 @@ namespace currency std::string meta_info; crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8 bool hidden_supply = false; + uint8_t version = ASSET_DESCRIPTOR_BASE_HF4_VER; + //version 1 members boost::optional owner_eth_pub_key; // note: the size is 33 bytes (if present) // NOTE: using boost::optional instead of std::optional because of the Boost compilation issue: https://github.com/boostorg/serialization/issues/319 -- sowle + //version 2 members + std::vector etc; //container for future use if we would be adding some optional parameters that is not known yet, but without mess related to format version - uint8_t version = ASSET_DESCRIPTOR_BASE_STRUCTURE_VER; - BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_BASE_STRUCTURE_VER, version) + BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_BASE_LAST_VER, version) FIELD(total_max_supply) FIELD(current_supply) FIELD(decimal_point) @@ -725,8 +742,11 @@ namespace currency FIELD(hidden_supply) END_VERSION_UNDER(1) FIELD(owner_eth_pub_key) + END_VERSION_UNDER(2) + FIELD(etc) END_SERIALIZE() + BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(2) BEGIN_BOOST_SERIALIZATION() BOOST_SERIALIZE(total_max_supply) BOOST_SERIALIZE(current_supply) @@ -738,7 +758,10 @@ namespace currency BOOST_SERIALIZE(hidden_supply) BOOST_END_VERSION_UNDER(1) BOOST_SERIALIZE(owner_eth_pub_key) - END_BOOST_SERIALIZATION() + BOOST_END_VERSION_UNDER(2) + BOOST_SERIALIZE(etc) + BOOST_SERIALIZE(version) + END_BOOST_SERIALIZATION_TOTAL_FIELDS(11) BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for a given asset, cannot be changed after deployment.") DOC_EXMP(1000000000000000000) DOC_END @@ -778,38 +801,62 @@ namespace currency #define ASSET_DESCRIPTOR_OPERATION_UPDATE 3 #define ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN 4 -#define ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER 1 +#define ASSET_DESCRIPTOR_OPERATION_HF4_VER 1 +#define ASSET_DESCRIPTOR_OPERATION_HF5_VER 2 +#define ASSET_DESCRIPTOR_OPERATION_LAST_VER 2 + + typedef boost::variant asset_descriptor_operation_etc_fields; struct asset_descriptor_operation { - uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; - asset_descriptor_base descriptor; - crypto::public_key amount_commitment; // premultiplied by 1/8 - boost::optional opt_asset_id; // target asset_id - for update/emit - uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER; + uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; + uint8_t version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; + // register emit burn update + boost::optional opt_amount_commitment; // + + + - (premultiplied by 1/8) + boost::optional opt_asset_id; // - + + + + boost::optional opt_descriptor; // + - - + + boost::optional opt_amount; // ? ? ? - (only for non-hidden supply) + boost::optional opt_asset_id_salt; // ? - - - (optional) + std::vector etc; // (reserved for future use) - BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER, verion) + + BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_LAST_VER, version) + CHAIN_TRANSITION_VER(0, asset_descriptor_operation_v1) + CHAIN_TRANSITION_VER(1, asset_descriptor_operation_v1) FIELD(operation_type) - FIELD(descriptor) - FIELD(amount_commitment) - END_VERSION_UNDER(1) + FIELD(opt_amount_commitment) FIELD(opt_asset_id) + FIELD(opt_descriptor) + FIELD(opt_amount) + FIELD(opt_asset_id_salt) + FIELD(etc) END_SERIALIZE() + BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(2) BEGIN_BOOST_SERIALIZATION() + BOOST_CHAIN_TRANSITION_VER(1, asset_descriptor_operation_v1) + BOOST_CHAIN_TRANSITION_VER(0, asset_descriptor_operation_v1) + BOOST_SERIALIZE(version) BOOST_SERIALIZE(operation_type) - BOOST_SERIALIZE(descriptor) - BOOST_SERIALIZE(amount_commitment) - BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(opt_amount_commitment) BOOST_SERIALIZE(opt_asset_id) - END_BOOST_SERIALIZATION() + BOOST_SERIALIZE(opt_descriptor) + BOOST_SERIALIZE(opt_amount) + BOOST_SERIALIZE(opt_asset_id_salt) + BOOST_SERIALIZE(etc) + END_BOOST_SERIALIZATION_TOTAL_FIELDS(8) BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(operation_type) DOC_DSCR("Asset operation type identifier") DOC_EXMP(1) DOC_END - KV_SERIALIZE(descriptor) DOC_DSCR("Asset descriptor") DOC_EXMP_AUTO() DOC_END - KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitment) DOC_DSCR("Amount commitment") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END - KV_SERIALIZE_POD_AS_HEX_STRING(opt_asset_id) DOC_DSCR("ID of an asset.") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END + KV_SERIALIZE(version) DOC_DSCR("Asset operation type struct version") DOC_EXMP(2) DOC_END + KV_SERIALIZE(operation_type) DOC_DSCR("Asset operation type identifier") DOC_EXMP(1) DOC_END + KV_SERIALIZE_POD_AS_HEX_STRING(opt_amount_commitment) DOC_DSCR("(optional) Asset operation amount commitment (register/emit/burn).") DOC_EXMP("5688b56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END + KV_SERIALIZE_POD_AS_HEX_STRING(opt_asset_id) DOC_DSCR("(optional) ID of an asset (emit/burn/update).") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END + KV_SERIALIZE(opt_descriptor) DOC_DSCR("(optional) Asset operation descriptor (register/update).") DOC_EXMP_AUTO() DOC_END + KV_SERIALIZE(opt_amount) DOC_DSCR("(optional) Asset operation amount (register/emit/burn when supply is non-hidden).") DOC_EXMP_AUTO() DOC_END + KV_SERIALIZE(opt_asset_id_salt) DOC_DSCR("(optional) Asset ID salt. May only be used for asset registration.") DOC_EXMP_AUTO() DOC_END + //KV_SERIALIZE(etc) DOC_DSCR("Extra operations") DOC_EXMP_AUTO() DOC_END <---- serialization for variant not supported yet END_KV_SERIALIZE_MAP() + }; struct asset_operation_proof @@ -824,6 +871,7 @@ namespace currency FIELD(opt_amount_commitment_g_proof) END_SERIALIZE() + BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(1) BEGIN_BOOST_SERIALIZATION() BOOST_SERIALIZE(opt_amount_commitment_composition_proof) BOOST_SERIALIZE(opt_amount_commitment_g_proof) @@ -842,6 +890,7 @@ namespace currency FIELD(gss) END_SERIALIZE() + BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(1) BEGIN_BOOST_SERIALIZATION() BOOST_SERIALIZE(gss) BOOST_END_VERSION_UNDER(1) @@ -1023,6 +1072,19 @@ namespace currency FIELD(signatures) FIELD(proofs) END_SERIALIZE() + + + BOOST_SERIALIZATION_CURRENT_ARCHIVE_VER(0) + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(version) + BOOST_SERIALIZE(vin) + BOOST_SERIALIZE(vout) + BOOST_SERIALIZE(extra) + BOOST_SERIALIZE(signatures) + BOOST_SERIALIZE(attachment) + BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(proofs) + END_BOOST_SERIALIZATION() }; @@ -1158,9 +1220,12 @@ BLOB_SERIALIZER(currency::txout_to_key); VARIANT_TAG(json_archive, type_name, json_tag) -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); + +LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_descriptor_operation); +LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_descriptor_base); +LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_operation_proof); +LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::asset_operation_ownership_proof); +LOOP_BACK_BOOST_SERIALIZATION_VERSION(currency::transaction); // txin_v variant currency @@ -1235,7 +1300,8 @@ SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation SET_VARIANT_TAGS(currency::asset_operation_ownership_proof_eth, 52, "asset_operation_ownership_proof_eth"); SET_VARIANT_TAGS(crypto::eth_public_key, 60, "eth_public_key"); -//SET_VARIANT_TAGS(crypto::eth_signature, 61, "eth_signature");s +//SET_VARIANT_TAGS(crypto::eth_signature, 61, "eth_signature"); +SET_VARIANT_TAGS(currency::dummy, 62, "dummy"); diff --git a/src/currency_core/currency_basic_backward_comp.inl b/src/currency_core/currency_basic_backward_comp.inl index 7dffea0e..9dc2a903 100644 --- a/src/currency_core/currency_basic_backward_comp.inl +++ b/src/currency_core/currency_basic_backward_comp.inl @@ -116,3 +116,74 @@ bool transition_convert(const transaction_v1& from, transaction_current_t& to) } return true; } + +struct asset_descriptor_operation_v1 +{ + uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; + asset_descriptor_base descriptor; + crypto::public_key amount_commitment = currency::null_pkey; // premultiplied by 1/8 + boost::optional opt_asset_id; // target asset_id - for update/emit + uint8_t verion = ASSET_DESCRIPTOR_OPERATION_HF4_VER; + + BEGIN_SERIALIZE() + FIELD(operation_type) + FIELD(descriptor) + FIELD(amount_commitment) + //END_VERSION_UNDER(1) + FIELD(opt_asset_id) + END_SERIALIZE() + + + //this map doesn't store internal version member, but it set it by default to val "1", which then transfered via transition_convert() to destination struct + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(operation_type) + BOOST_SERIALIZE(descriptor) + BOOST_SERIALIZE(amount_commitment) + //BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(opt_asset_id) + END_BOOST_SERIALIZATION() +}; + +template +bool transition_convert(const asset_descriptor_operation_t& from, asset_descriptor_operation_v1& to) +{ + to.verion = from.version; + to.operation_type = from.operation_type; + if(from.opt_descriptor.has_value()) + { + to.descriptor = *from.opt_descriptor; + } + else + { + throw std::runtime_error(std::string("Unexpected: missing descriptor in from transaction_current_t")); + } + + if (from.opt_amount_commitment.has_value()) + { + to.amount_commitment = *from.opt_amount_commitment; + } + else + { + //not used over update operations //throw std::runtime_error(std::string("Unexpected: missing amount_commitment in from transaction_current_t")); + } + + to.opt_asset_id = from.opt_asset_id; + + if(from.opt_amount.has_value() || from.etc.size()) + { + throw std::runtime_error(std::string("Unexpected: opt_amount or etc have values during convention, looks like object slicing with information getting lost")); + } + + return true; +} + +template +bool transition_convert(const asset_descriptor_operation_v1& from, asset_descriptor_operation_t& to) +{ + to.operation_type = from.operation_type; + to.opt_descriptor = from.descriptor; + to.opt_amount_commitment = from.amount_commitment; + to.opt_asset_id = from.opt_asset_id; // target asset_id - for update/emit + to.version = from.verion; + return true; +} \ No newline at end of file diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h index 5d7c40f7..c12caf25 100644 --- a/src/currency_core/currency_boost_serialization.h +++ b/src/currency_core/currency_boost_serialization.h @@ -222,16 +222,7 @@ namespace boost a & x.buff; } - template - inline void serialize(Archive &a, currency::transaction &x, const boost::serialization::version_type ver) - { - a & x.version; - a & x.vin; - a & x.vout; - a & x.extra; - a & x.signatures; - a & x.attachment; - } + template inline void serialize(Archive &a, currency::keypair &kp, const boost::serialization::version_type ver) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index ff666f50..1d6edf20 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -10,7 +10,7 @@ #ifndef TESTNET #define CURRENCY_FORMATION_VERSION 84 #else -#define CURRENCY_FORMATION_VERSION 98 +#define CURRENCY_FORMATION_VERSION 99 #endif #define CURRENCY_GENESIS_NONCE (CURRENCY_FORMATION_VERSION + 101011010121) //bender's nightmare @@ -118,7 +118,7 @@ #define P2P_MAINTAINERS_PUB_KEY "8f138bb73f6d663a3746a542770781a09579a7b84cb4125249e95530824ee607" #define DIFFICULTY_POS_STARTER 1 #else -#define P2P_DEFAULT_PORT (11112 + CURRENCY_FORMATION_VERSION) +#define P2P_DEFAULT_PORT (11211 + CURRENCY_FORMATION_VERSION) #define RPC_DEFAULT_PORT 12111 #define STRATUM_DEFAULT_PORT 11888 #define STRARUM_DEFAULT_PORT 51113 @@ -253,7 +253,7 @@ #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" -#define WALLET_FILE_SERIALIZATION_VERSION 167 +#define WALLET_FILE_SERIALIZATION_VERSION 168 #define WALLET_FILE_LAST_SUPPORTED_VERSION 165 #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) @@ -271,16 +271,16 @@ #define ZANO_HARDFORK_04_AFTER_HEIGHT 2555000 // 2024-03-21 11:49:55 #define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1711021795ull // block 2555000, 2024-03-21 11:49:55 UTC #define ZANO_HARDFORK_05_AFTER_HEIGHT 999999999999999999 -#define ZANO_HARDFORK_05_MIN_BUILD_VER 343 +#define ZANO_HARDFORK_05_MIN_BUILD_VER 354 #else // Testnet #define ZANO_HARDFORK_01_AFTER_HEIGHT 0 #define ZANO_HARDFORK_02_AFTER_HEIGHT 0 #define ZANO_HARDFORK_03_AFTER_HEIGHT 0 -#define ZANO_HARDFORK_04_AFTER_HEIGHT 200 -#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1712785801ull // block 200, 2024-04-10 21:50:01 UTC -#define ZANO_HARDFORK_05_AFTER_HEIGHT 241750 -#define ZANO_HARDFORK_05_MIN_BUILD_VER 343 +#define ZANO_HARDFORK_04_AFTER_HEIGHT 100 +#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1712800000ull // block 100, 2024-00-00 00:00:00 UTC +#define ZANO_HARDFORK_05_AFTER_HEIGHT 200 +#define ZANO_HARDFORK_05_MIN_BUILD_VER 356 #endif diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 7df55765..96d55b46 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -197,17 +197,17 @@ namespace currency return true; } //-------------------------------------------------------------------------------- - bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, const tx_generation_context& outs_gen_context, + bool generate_zc_outs_range_proof(const crypto::hash& context_hash, const tx_generation_context& outs_gen_context, const std::vector& vouts, zc_outs_range_proof& result) { size_t outs_count = outs_gen_context.amounts.size(); // TODO @#@# reconsider this check CHECK_AND_ASSERT_MES(gen_context.check_sizes(outs_count), false, ""); - CHECK_AND_ASSERT_MES(out_index_start + outs_count == vouts.size(), false, ""); + CHECK_AND_ASSERT_MES(outs_count == vouts.size(), false, ""); // prepare data for aggregation proof std::vector amount_commitments_for_rp_aggregation; // E' = amount * U + y' * G crypto::scalar_vec_t y_primes; // y' - for (size_t out_index = out_index_start, i = 0; i < outs_count; ++out_index, ++i) + for (size_t i = 0; i < outs_count; ++i) { crypto::scalar_t y_prime = crypto::scalar_t::random(); amount_commitments_for_rp_aggregation.emplace_back(outs_gen_context.amounts[i] * crypto::c_point_U + y_prime * crypto::c_point_G); // E'_j = e_j * U + y'_j * G @@ -564,7 +564,7 @@ namespace currency // range proofs currency::zc_outs_range_proof range_proofs{}; - r = generate_zc_outs_range_proof(tx_id, 0, tx_gen_context, tx.vout, range_proofs); + r = generate_zc_outs_range_proof(tx_id, tx_gen_context, tx.vout, range_proofs); CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()"); tx.proofs.emplace_back(std::move(range_proofs)); @@ -609,7 +609,7 @@ namespace currency 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); - if (context.ado.descriptor.hidden_supply) + if (context.ado.opt_descriptor.has_value() && context.ado.opt_descriptor->hidden_supply) { CHECK_AND_ASSERT_MES(aop.opt_amount_commitment_composition_proof.has_value(), false, "opt_amount_commitment_composition_proof is absent"); // TODO @#@# if asset is hidden -- check composition proof @@ -619,7 +619,8 @@ namespace currency { // make sure that amount commitment corresponds to opt_amount_commitment_g_proof CHECK_AND_ASSERT_MES(aop.opt_amount_commitment_g_proof.has_value(), false, "opt_amount_commitment_g_proof is absent"); - crypto::point_t A = crypto::point_t(context.ado.amount_commitment).modify_mul8() - context.amount_to_validate * context.asset_id_pt; + CHECK_AND_ASSERT_MES(context.ado.opt_amount_commitment.has_value(), false, "amount_commitment is absent"); + crypto::point_t A = crypto::point_t(context.ado.opt_amount_commitment.get()).modify_mul8() - context.amount_to_validate * context.asset_id_pt; bool r = crypto::check_signature(context.tx_id, A.to_public_key(), aop.opt_amount_commitment_g_proof.get()); CHECK_AND_ASSERT_MES(r, false, "opt_amount_commitment_g_proof check failed"); @@ -675,12 +676,14 @@ namespace currency { if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) { + CHECK_AND_ASSERT_MES(ado.opt_amount_commitment.has_value(), false, "opt_amount_commitment is missing"); // 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 + sum_of_pseudo_out_amount_commitments += crypto::point_t(ado.opt_amount_commitment.get()); // *1/8 } else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) { - outs_commitments_sum += crypto::point_t(ado.amount_commitment); // *1/8 + CHECK_AND_ASSERT_MES(ado.opt_amount_commitment.has_value(), false, "opt_amount_commitment is missing"); + outs_commitments_sum += crypto::point_t(ado.opt_amount_commitment.get()); // *1/8 } } size_t zc_sigs_count = 0; @@ -2186,18 +2189,23 @@ namespace currency // otherwise, it must be a register operation CHECK_AND_ASSERT_MES(ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unexpected asset operation type: " << (int)ado.operation_type << ", " << get_asset_operation_type_string(ado.operation_type)); + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing: " << (int)ado.operation_type << ", " << get_asset_operation_type_string(ado.operation_type)); + const asset_descriptor_base &adb = ado.opt_descriptor.get(); // 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); - if (ado.descriptor.owner_eth_pub_key.has_value()) - hsc.add_eth_pub_key(ado.descriptor.owner_eth_pub_key.value()); + hsc.add_hash(crypto::hash_helper_t::h(adb.ticker)); + hsc.add_hash(crypto::hash_helper_t::h(adb.full_name)); + hsc.add_hash(crypto::hash_helper_t::h(adb.meta_info)); + hsc.add_scalar(crypto::scalar_t(adb.total_max_supply)); + hsc.add_scalar(crypto::scalar_t(adb.decimal_point)); + hsc.add_pub_key(adb.owner); + if (adb.owner_eth_pub_key.has_value()) + hsc.add_eth_pub_key(adb.owner_eth_pub_key.value()); + if (ado.opt_asset_id_salt.has_value()) + hsc.add_scalar(crypto::scalar_t(ado.opt_asset_id_salt.get())); + crypto::hash h = hsc.calc_hash_no_reduce(); // this hash function needs to be computationally expensive (s.a. the whitepaper) @@ -2242,16 +2250,11 @@ 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"); - // - // 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 + CHECK_AND_ASSERT_MES(ado.opt_descriptor.has_value(), false, "opt_descriptor is missing (register)"); + asset_descriptor_base& adb = ado.opt_descriptor.get(); - if (!ado.descriptor.owner_eth_pub_key.has_value()) - ado.descriptor.owner = sender_account_keys.account_address.spend_public_key; + if (!adb.owner_eth_pub_key.has_value()) + adb.owner = sender_account_keys.account_address.spend_public_key; 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"); @@ -2268,10 +2271,14 @@ namespace currency amount_of_emitted_asset += item.amount; } } - ado.descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle + adb.current_supply = amount_of_emitted_asset; + if (ado.version >= ASSET_DESCRIPTOR_BASE_HF5_VER) + { + ado.opt_amount = amount_of_emitted_asset; // TODO: support hidden supply -- sowle + } gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; - ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + ado.opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); } else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) { @@ -2281,7 +2288,7 @@ namespace currency 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 + // calculate the amount of asset being burnt using asset_id field in inputs and outputs (sources and destinations) uint64_t amount_of_burned_assets = 0; for (auto& item : ftp.sources) { @@ -2298,10 +2305,19 @@ namespace currency amount_of_burned_assets -= item.amount; } } - ado.descriptor.current_supply -= amount_of_burned_assets; - + if (ado.version < ASSET_DESCRIPTOR_BASE_HF5_VER) + { + CHECK_AND_ASSERT_THROW_MES(ado.opt_descriptor.has_value(), "Internal error: opt_descriptor unset during ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN for version less then 2"); + ado.opt_descriptor->current_supply -= amount_of_burned_assets; + } + else + { + CHECK_AND_ASSERT_THROW_MES(!ado.opt_descriptor.has_value(), "Internal error: opt_descriptor unset during ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN for version less then 2"); + ado.opt_amount = amount_of_burned_assets; // TODO: support hidden supply -- sowle + } + gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; - ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + ado.opt_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 }); @@ -2325,10 +2341,19 @@ namespace currency item.asset_id = gen_context.ao_asset_id; } } - ado.descriptor.current_supply += amount_of_emitted_asset; + if (ado.version < ASSET_DESCRIPTOR_BASE_HF5_VER) + { + CHECK_AND_ASSERT_THROW_MES(ado.opt_descriptor.has_value(), "Internal error: opt_descriptor unset during ASSET_DESCRIPTOR_OPERATION_EMIT for version less then 2"); + ado.opt_descriptor->current_supply += amount_of_emitted_asset; + } + else + { + CHECK_AND_ASSERT_THROW_MES(!ado.opt_descriptor.has_value(), "Internal error: opt_descriptor unset during ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN for version less then 2"); + ado.opt_amount = amount_of_emitted_asset; // TODO: support hidden supply -- sowle + } gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; - ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + ado.opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); } else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) @@ -2607,7 +2632,6 @@ namespace currency // construct outputs uint64_t native_coins_output_sum = 0; size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1 - uint64_t range_proof_start_index = 0; std::set existing_derivation_hints, new_derivation_hints; CHECK_AND_ASSERT_MES(copy_all_derivation_hints_from_tx_to_container(tx, existing_derivation_hints), false, "move_all_derivation_hints_from_tx_to_container failed"); for(size_t destination_index = 0; destination_index < shuffled_dsts.size(); ++destination_index, ++output_index) @@ -2749,7 +2773,7 @@ namespace currency // range proofs currency::zc_outs_range_proof range_proofs{}; - r = generate_zc_outs_range_proof(tx_prefix_hash, range_proof_start_index, gen_context, tx.vout, range_proofs); + r = generate_zc_outs_range_proof(tx_prefix_hash, gen_context, tx.vout, range_proofs); CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()"); tx.proofs.emplace_back(std::move(range_proofs)); @@ -2774,8 +2798,7 @@ namespace currency const asset_descriptor_operation* pado = get_type_in_variant_container(tx.extra); if (pado != nullptr) { - if ((pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || pado->operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) && - !pado->descriptor.owner_eth_pub_key.has_value()) + if ((pado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || pado->operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) && (!ftp.ado_sign_thirdparty)) { asset_operation_ownership_proof aoop{}; r = crypto::generate_schnorr_sig(tx_prefix_hash, sender_account_keys.spend_secret_key, aoop.gss); @@ -3609,13 +3632,13 @@ namespace currency return true; } //------------------------------------------------------------------ + #define PASSWORD_REGEXP R"([A-Za-z0-9~!?@#$%^&*_+|{}\[\]()<>:;"'\-=/.,]{0,40})" bool validate_password(const std::string& password) { - static const std::string allowed_password_symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!?@#$%^&*_+|{}[]()<>:;\"'-=\\/.,"; - size_t n = password.find_first_not_of(allowed_password_symbols, 0); - return n == std::string::npos; + // OLD: static const std::string allowed_password_symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~!?@#$%^&*_+|{}[]()<>:;\"'-=\\/.,"; + static std::regex password_regexp(PASSWORD_REGEXP); + return std::regex_match(password, password_regexp); } - //------------------------------------------------------------------ #define ANTI_OVERFLOW_AMOUNT 1000000 #define GET_PERECENTS_BIG_NUMBERS(per, total) (per/ANTI_OVERFLOW_AMOUNT)*100 / (total/ANTI_OVERFLOW_AMOUNT) @@ -4442,8 +4465,8 @@ namespace currency } } //------------------------------------------------------------------ -#define ASSET_TICKER_REGEXP "[A-Za-z0-9]{1,14}" -#define ASSET_FULL_NAME_REGEXP "[A-Za-z0-9.,:!?\\-() ]{0,400}" +#define ASSET_TICKER_REGEXP R"([A-Za-z0-9]{1,14})" +#define ASSET_FULL_NAME_REGEXP R"([A-Za-z0-9.,:!?\-() ]{0,400})" bool validate_asset_ticker(const std::string& ticker) { static std::regex asset_ticker_regexp(ASSET_TICKER_REGEXP); diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 2fab77e1..399a6d90 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -29,6 +29,7 @@ #include "currency_format_utils_transactions.h" #include "core_runtime_config.h" #include "wallet/wallet_public_structs_defs.h" +#include "wallet/wallet_public_structs_defs.h" #include "bc_attachments_helpers.h" #include "bc_payments_id_service.h" #include "bc_offers_service_basic.h" @@ -164,9 +165,11 @@ namespace currency uint64_t tx_version; uint64_t mode_separate_fee = 0; - epee::misc_utils::events_dispatcher* pevents_dispatcher; + epee::misc_utils::events_dispatcher* pevents_dispatcher = nullptr; tx_generation_context gen_context{}; // solely for consolidated txs + + bool ado_sign_thirdparty = false;//@#@ TODO: add to serialization map @zoidberg BEGIN_SERIALIZE_OBJECT() @@ -259,6 +262,7 @@ namespace currency const transaction& tx; const crypto::hash& tx_id; const asset_descriptor_operation& ado; + uint64_t height = UINT64_MAX; // default value means the height of the upcoming block (top_block + 1) crypto::public_key asset_id = currency::null_pkey; crypto::point_t asset_id_pt = crypto::c_point_0; uint64_t amount_to_validate = 0; @@ -269,7 +273,7 @@ namespace currency bool generate_asset_surjection_proof(const crypto::hash& context_hash, bool has_non_zc_inputs, tx_generation_context& ogc, zc_asset_surjection_proof& result); bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id); bool generate_tx_balance_proof(const transaction &tx, const crypto::hash& tx_id, const tx_generation_context& ogc, uint64_t block_reward_for_miner_tx, zc_balance_proof& proof); - bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, const tx_generation_context& outs_gen_context, + bool generate_zc_outs_range_proof(const crypto::hash& context_hash, const tx_generation_context& outs_gen_context, 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); @@ -950,6 +954,7 @@ namespace currency } } } + /* //--------------------------------------------------------------- template typename std::enable_if_t, std::ostream&> operator<<(std::ostream& o, invocable_t callee) @@ -957,6 +962,7 @@ namespace currency callee(o); return o; } + */ //--------------------------------------------------------------- std::ostream& operator <<(std::ostream& o, const ref_by_id& r); std::ostream& operator <<(std::ostream& o, const std::type_info& ti); @@ -1214,7 +1220,13 @@ namespace currency tv.short_view = std::string("op:") + get_asset_operation_type_string(ado.operation_type, true); if (ado.opt_asset_id.has_value()) tv.short_view += std::string(" , id:") + crypto::pod_to_hex(ado.opt_asset_id); - tv.details_view = tv.short_view + std::string(" , ticker:") + ado.descriptor.ticker + std::string(" , cur.supply:") + print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point); + tv.details_view = tv.short_view; + if (ado.opt_descriptor.has_value()) + { + tv.details_view += std::string(" , ticker:") + ado.opt_descriptor->ticker + std::string(" , cur.supply:") + print_money_brief(ado.opt_descriptor->current_supply, ado.opt_descriptor->decimal_point); + } + //@#@ TODO: add other info from asset_descriptor_operation v2+ + return true; } template diff --git a/src/currency_core/miner.cpp b/src/currency_core/miner.cpp index d52e51e2..109d9966 100644 --- a/src/currency_core/miner.cpp +++ b/src/currency_core/miner.cpp @@ -40,24 +40,25 @@ namespace currency } - miner::miner(i_miner_handler* phandler, blockchain_storage& bc):m_stop(1), - //m_bc(bc), - m_template(boost::value_initialized()), - m_template_no(0), - m_diffic(0), - m_thread_index(0), - m_phandler(phandler), - m_height(0), - m_pausers_count(0), - m_threads_total(0), - m_starter_nonce(0), - m_do_print_hashrate(false), - m_do_mining(false), - m_current_hash_rate(0), - m_last_hr_merge_time(0), - m_hashes(0), - m_config(AUTO_VAL_INIT(m_config)), - m_mine_address{} + miner::miner(i_miner_handler* phandler, blockchain_storage& bc) + : m_stop(1) + , m_template(boost::value_initialized()) + , m_template_no(0) + , m_diffic(0) + , m_thread_index(0) + , m_phandler(phandler) + , m_height(0) + , m_pausers_count(0) + , m_block_template_ready(false) + , m_threads_total(0) + , m_starter_nonce(0) + , m_do_print_hashrate(false) + , m_do_mining(false) + , m_current_hash_rate(0) + , m_last_hr_merge_time(0) + , m_hashes(0) + , m_config(AUTO_VAL_INIT(m_config)) + , m_mine_address{} { } //----------------------------------------------------------------------------------------------------- @@ -76,6 +77,7 @@ namespace currency m_height = height; ++m_template_no; m_starter_nonce = crypto::rand(); + m_block_template_ready = true; return true; } //----------------------------------------------------------------------------------------------------- @@ -100,7 +102,8 @@ namespace currency } if(!m_phandler->get_block_template(bl, m_mine_address, m_mine_address, di, height, extra_nonce)) { - LOG_ERROR("Failed to get_block_template()"); + // it's quite possible that block template cannot be created at particular time; need to wait + m_block_template_ready = false; return false; } set_block_template(bl, di, height); @@ -110,7 +113,8 @@ namespace currency bool miner::on_idle() { m_update_block_template_interval.do_call([&](){ - if(is_mining())request_block_template(); + if(is_mining()) + request_block_template(); return true; }); @@ -233,8 +237,13 @@ namespace currency return false; } - if(!m_template_no) - request_block_template();//lets update block template + while(!m_template_no) + { + if (request_block_template()) + break; + std::this_thread::sleep_for(std::chrono::seconds(2)); + LOG_PRINT_L1("Trying to get block template...."); + } boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0); boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0); @@ -313,12 +322,11 @@ namespace currency uint64_t local_height = 0; crypto::hash local_blob_data_hash = null_hash; - //uint64_t local_template_height = 0; - block b; + block b{}; while(!m_stop) { - if(m_pausers_count)//anti split workaround + if(m_pausers_count != 0 || !m_block_template_ready) { misc_utils::sleep_no_w(100); continue; diff --git a/src/currency_core/miner.h b/src/currency_core/miner.h index 94caea2b..c8a37225 100644 --- a/src/currency_core/miner.h +++ b/src/currency_core/miner.h @@ -101,6 +101,7 @@ namespace currency volatile uint32_t m_thread_index; volatile uint32_t m_threads_total; std::atomic m_pausers_count; + std::atomic m_block_template_ready; epee::critical_section m_miners_count_lock; std::list m_threads; diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp index 33315870..d076d147 100644 --- a/src/currency_core/tx_pool.cpp +++ b/src/currency_core/tx_pool.cpp @@ -247,7 +247,7 @@ namespace currency r = process_type_in_variant_container_and_make_sure_its_unique(tx.extra, [&](const asset_descriptor_operation& ado){ asset_op_verification_context avc = { tx, id, ado }; - return m_blockchain.validate_asset_operation_against_current_blochain_state(avc); + return m_blockchain.validate_asset_operation(avc, m_blockchain.get_current_blockchain_size()); }, true); CHECK_AND_ASSERT_MES_CUSTOM(r, false, { tvc.m_verification_failed = true; }, "post-HF4 tx: asset operation is invalid"); } diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index c960a39c..1b26fb73 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -48,6 +48,7 @@ public: m_cmd_binder.set_handler("print_tx_prun_info", boost::bind(&daemon_commands_handler::print_tx_prun_info, this, ph::_1), "Print tx prunning info"); m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_commands_handler::print_tx, this, ph::_1), "Print transaction, print_tx "); m_cmd_binder.set_handler("print_asset_info", boost::bind(&daemon_commands_handler::print_asset_info, this, ph::_1), "Print information about the given asset by its id"); + m_cmd_binder.set_handler("print_blocked_ips", boost::bind(&daemon_commands_handler::print_blocked_ips, this, ph::_1), "Print ip address blacklists"); m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_commands_handler::start_mining, this, ph::_1), "Start mining for specified address, start_mining [threads=1]"); m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_commands_handler::stop_mining, this, ph::_1), "Stop mining"); m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_commands_handler::print_pool, this, ph::_1), "Print transaction pool (long format)"); @@ -235,6 +236,20 @@ private: return true; } //-------------------------------------------------------------------------------- + bool print_blocked_ips(const std::vector& args) + { + std::map blocklist; + m_srv.get_ip_block_list(blocklist); + std::stringstream ss; + ss << "BLOCKED IPS:" << ENDL; + for (const auto& e : blocklist) + { + ss << string_tools::get_ip_string_from_int32(e.first) << ", time: " << std::put_time(std::localtime(&e.second), "%Y-%m-%d %H:%M:%S") << ENDL; + } + LOG_PRINT_L0(ss.str()); + return true; + } + //-------------------------------------------------------------------------------- bool print_bc(const std::vector& args) { if (!args.size()) @@ -806,17 +821,21 @@ private: size_t idx = 0; for(auto& aop: asset_history) { - ss << "[" << std::setw(2) << idx << "] operation: " << currency::get_asset_operation_type_string(aop.operation_type) << " (" << (int)aop.operation_type << ")" << ENDL << - " ticker: \"" << aop.descriptor.ticker << "\"" << ENDL << - " full name: \"" << aop.descriptor.full_name << "\"" << ENDL << - " meta info: \"" << aop.descriptor.meta_info << "\"" << ENDL << - " current supply: " << currency::print_money_brief(aop.descriptor.current_supply, aop.descriptor.decimal_point) << ENDL << - " max supply: " << currency::print_money_brief(aop.descriptor.total_max_supply, aop.descriptor.decimal_point) << ENDL << - " decimal point: " << (int)aop.descriptor.decimal_point << ENDL << - " owner * 1/8: " << aop.descriptor.owner << ENDL << - " amount cmt * 1/8: " << aop.amount_commitment << ENDL << - " hidden supply: " << (aop.descriptor.hidden_supply ? "yes" : "no") << ENDL << - ""; + if (aop.opt_descriptor.has_value()) + { + const currency::asset_descriptor_base& adb = aop.opt_descriptor.value(); + ss << "[" << std::setw(2) << idx << "] operation: " << currency::get_asset_operation_type_string(aop.operation_type) << " (" << (int)aop.operation_type << ")" << ENDL << + " ticker: \"" << adb.ticker << "\"" << ENDL << + " full name: \"" << adb.full_name << "\"" << ENDL << + " meta info: \"" << adb.meta_info << "\"" << ENDL << + " current supply: " << currency::print_money_brief(adb.current_supply, adb.decimal_point) << ENDL << + " max supply: " << currency::print_money_brief(adb.total_max_supply, adb.decimal_point) << ENDL << + " decimal point: " << (int)adb.decimal_point << ENDL << + " owner * 1/8: " << adb.owner << ENDL << + " amount cmt * 1/8: " << (aop.opt_amount_commitment.has_value() ? aop.opt_amount_commitment.value() : currency::null_pkey) << ENDL << + " hidden supply: " << (adb.hidden_supply ? "yes" : "no") << ENDL << + ""; + } ++idx; } diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 5c878005..7cd0e5e5 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 5c878005ace55484eafe2985d204cd51e90b203b +Subproject commit 7cd0e5e54a0d692ea819b9653f60a1cd5512dc2b diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 9ec3cc17..38b5a5ab 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -121,6 +121,7 @@ namespace nodetool peerlist_manager& get_peerlist_manager(){return m_peerlist;} bool handle_maintainers_entry(const maintainers_entry& me); bool get_maintainers_info(maintainers_info_external& me); + void get_ip_block_list(std::map& blocklist); typedef COMMAND_REQUEST_STAT_INFO_T COMMAND_REQUEST_STAT_INFO; private: diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 70b906dc..fb1c4109 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -448,6 +448,13 @@ namespace nodetool } //----------------------------------------------------------------------------------- template + void node_server::get_ip_block_list(std::map& blocklist) + { + CRITICAL_REGION_LOCAL(m_blocked_ips_lock); + blocklist = m_blocked_ips; + } + //----------------------------------------------------------------------------------- + template bool node_server::on_maintainers_entry_update() { LOG_PRINT_CHANNEL_COLOR2(NULL, NULL, "Fresh maintainers info recieved(timestamp: " << m_maintainers_info_local.timestamp << ")", LOG_LEVEL_0, epee::log_space::console_color_magenta); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 7960328f..9a5d07e2 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -591,6 +591,12 @@ bool simple_wallet::try_connect_to_daemon() //---------------------------------------------------------------------------------------------------- bool simple_wallet::new_wallet(const string &wallet_file, const std::string& password, bool create_auditable_wallet) { + if (!currency::validate_password(password)) + { + fail_msg_writer() << R"(Provided password contains invalid characters. Only letters, numbers and ~!?@#$%^&*_+|{}[]()<>:;"'-=/., symbols are allowed.)" << ENDL; + return false; + } + m_wallet_file = wallet_file; m_wallet.reset(new tools::wallet2()); @@ -1202,7 +1208,7 @@ bool simple_wallet::show_staking_history(const std::vector& args) bool transfers_found = false; for (auto it = transfers.rbegin(); it != transfers.rend(); it++) { - const auto& td = *it; + const auto& td = it->second; if (timestamp && td.m_ptx_wallet_info->m_block_timestamp < timestamp) break; @@ -1264,8 +1270,9 @@ bool simple_wallet::show_incoming_transfers(const std::vector& args m_wallet->get_transfers(transfers); bool transfers_found = false; - for (const auto& td : transfers) + for (const auto& tr : transfers) { + const auto& td = tr.second; if (!filter || available != static_cast(td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT)) { if (!transfers_found) @@ -1308,8 +1315,9 @@ bool simple_wallet::show_incoming_transfers_counts(const std::vector &args) fail_msg_writer() << "Failed to load json file with asset specification: " << args[0]; return true; } + + if (!validate_asset_ticker_and_full_name(adb)) + { + fail_msg_writer() << "ticker or full_name are invalid (perhaps they contain invalid symbols)"; + return true; + } + tx_destination_entry td = AUTO_VAL_INIT(td); td.addr.push_back(m_wallet->get_account().get_public_address()); td.amount = adb.current_supply; @@ -3140,7 +3155,7 @@ int wmain( int argc, wchar_t* argv_w[ ], wchar_t* envp[ ] ) int main(int argc, char* argv[]) #endif { -#ifdef WIN32 +#if defined(WIN32) && defined(_DEBUG) _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); //_CrtSetBreakAlloc(9594); #endif @@ -3472,7 +3487,7 @@ int main(int argc, char* argv[]) //runs wallet with console interface sw->set_offline_mode(offline_mode); r = sw->init(vm); - CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet"); + CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "Failed to initialize wallet"); if (command_line::get_arg(vm, arg_generate_new_wallet).size() || command_line::get_arg(vm, arg_generate_new_auditable_wallet).size()) return EXIT_FAILURE; diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 5f260433..d8bbb5d8 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -29,7 +29,7 @@ namespace currency typedef std::vector command_type; simple_wallet(); - ~simple_wallet(); + virtual ~simple_wallet(); bool init(const boost::program_options::variables_map& vm); bool deinit(); bool run(); diff --git a/src/version.h.in b/src/version.h.in index 1c544210..09597591 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -8,6 +8,6 @@ #define PROJECT_REVISION "1" #define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION -#define PROJECT_VERSION_BUILD_NO 352 +#define PROJECT_VERSION_BUILD_NO 366 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" diff --git a/src/wallet/core_default_rpc_proxy.cpp b/src/wallet/core_default_rpc_proxy.cpp index 4bd94188..38907e37 100644 --- a/src/wallet/core_default_rpc_proxy.cpp +++ b/src/wallet/core_default_rpc_proxy.cpp @@ -20,7 +20,11 @@ namespace tools { bool default_http_core_proxy::set_connection_addr(const std::string& url) { - m_daemon_address = url; + if (m_daemon_address != url) + { + m_daemon_address = url; + m_http_client.disconnect(); + } return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/wallet/plain_wallet_api.cpp b/src/wallet/plain_wallet_api.cpp index 3a9a1552..bb322481 100644 --- a/src/wallet/plain_wallet_api.cpp +++ b/src/wallet/plain_wallet_api.cpp @@ -56,6 +56,9 @@ void static_destroy_handler() LOG_PRINT_L0("[DESTROY CALLBACK HANDLER FINISHED]: "); } + + + namespace plain_wallet { struct plain_wallet_instance @@ -63,7 +66,9 @@ namespace plain_wallet plain_wallet_instance() :initialized(false), gjobs_counter(1) {} wallets_manager gwm; - std::atomic initialized; + std::atomic initialized = false; + std::atomic postponed_run_wallet = false; + std::atomic postponed_main_worked_started = false; std::atomic gjobs_counter; std::map gjobs; @@ -73,7 +78,6 @@ namespace plain_wallet std::shared_ptr ginstance_ptr; - typedef epee::json_rpc::response error_response; @@ -182,8 +186,11 @@ namespace plain_wallet } - std::string init(const std::string& ip, const std::string& port, const std::string& working_dir, int log_level) + std::string init(const std::string& ip_, const std::string& port_, const std::string& working_dir, int log_level) { + std::string ip = ip_; + std::string port = port_; + auto local_ptr = std::atomic_load(&ginstance_ptr); if (local_ptr) { @@ -197,6 +204,14 @@ namespace plain_wallet std::shared_ptr ptr(new plain_wallet_instance()); + if (ip.empty()) + { + ip = "0.0.0.0"; + port = "0"; + ptr->postponed_run_wallet = true; + } + + set_bundle_working_dir(working_dir); initialize_logs(log_level); @@ -217,10 +232,14 @@ namespace plain_wallet ptr->gwm.set_use_deffered_global_outputs(true); - if(!ptr->gwm.start()) + if (!ptr->postponed_run_wallet && !ptr->postponed_main_worked_started) { - LOG_ERROR("Failed to start wallets_manager"); - return GENERAL_INTERNAL_ERRROR_INIT; + if (!ptr->gwm.start()) + { + LOG_ERROR("Failed to start wallets_manager"); + return GENERAL_INTERNAL_ERRROR_INIT; + } + ptr->postponed_main_worked_started = true; } LOG_PRINT_L0("[INIT PLAIN_WALLET_INSTANCE] Ver:" << PROJECT_VERSION_LONG << "(" << BUILD_TYPE << ")"); @@ -261,11 +280,12 @@ namespace plain_wallet std::string init(const std::string& address, const std::string& working_dir, int log_level) { epee::net_utils::http::url_content url_data = AUTO_VAL_INIT(url_data); - if(!epee::net_utils::parse_url(address, url_data)) + if(!address.empty() && !epee::net_utils::parse_url(address, url_data)) { LOG_ERROR("Failed to parse address"); return API_RETURN_CODE_BAD_ARG; } + return init(url_data.host, std::to_string(url_data.port), working_dir, log_level); } @@ -438,7 +458,10 @@ namespace plain_wallet { ok_response.result.recovered = true; } - inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); + if (!inst_ptr->postponed_run_wallet) + { + inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); + } return epee::serialization::store_t_to_json(ok_response); } @@ -460,7 +483,10 @@ namespace plain_wallet { ok_response.result.recovered = true; } - inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); + if (!inst_ptr->postponed_run_wallet) + { + inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); + } return epee::serialization::store_t_to_json(ok_response); } error_response err_result = AUTO_VAL_INIT(err_result); @@ -481,7 +507,10 @@ namespace plain_wallet { ok_response.result.recovered = true; } - inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); + if (!inst_ptr->postponed_run_wallet) + { + inst_ptr->gwm.run_wallet(ok_response.result.wallet_id); + } return epee::serialization::store_t_to_json(ok_response); } error_response err_result = AUTO_VAL_INIT(err_result); @@ -550,6 +579,52 @@ namespace plain_wallet return std::string("{ \"job_id\": ") + std::to_string(job_id) + "}"; } + std::string handle_reset_connection_url(const std::string& url) + { + GET_INSTANCE_PTR(inst_ptr); + inst_ptr->gwm.set_remote_node_url(url); + + view::api_response ar = AUTO_VAL_INIT(ar); + ar.error_code = API_RETURN_CODE_OK; + return epee::serialization::store_t_to_json(ar); + } + + std::string handle_run_wallet(uint64_t instance_id) + { + GET_INSTANCE_PTR(inst_ptr); + + + //postponed worker loop launch + if (!inst_ptr->postponed_main_worked_started) + { + if (!inst_ptr->gwm.start()) + { + LOG_ERROR("Failed to start wallets_manager"); + return API_RETURN_CODE_INTERNAL_ERROR; + } + inst_ptr->postponed_main_worked_started = true; + } + + view::api_response ar = AUTO_VAL_INIT(ar); + ar.error_code = inst_ptr->gwm.run_wallet(instance_id); + return epee::serialization::store_t_to_json(ar); + } + + std::string handle_configure(const std::string& settings_json) + { + GET_INSTANCE_PTR(inst_ptr); + configure_object conf = AUTO_VAL_INIT(conf); + configure_response conf_resp = AUTO_VAL_INIT(conf_resp); + bool res = epee::serialization::load_t_from_json(conf, settings_json); + if (!res) + { + conf_resp.status = API_RETURN_CODE_BAD_ARG; + return epee::serialization::store_t_to_json(conf_resp); + } + inst_ptr->postponed_run_wallet = conf.postponed_run_wallet; + conf_resp.status = API_RETURN_CODE_OK; + return epee::serialization::store_t_to_json(conf_resp); + } std::string sync_call(const std::string& method_name, uint64_t instance_id, const std::string& params) { @@ -612,6 +687,18 @@ namespace plain_wallet { res = get_wallet_status(instance_id); } + else if (method_name == "configure") + { + res = handle_configure(params); + } + else if (method_name == "reset_connection_url") + { + res = handle_reset_connection_url(params); + } + else if (method_name == "run_wallet") + { + res = handle_run_wallet(instance_id); + } else { view::api_response ar = AUTO_VAL_INIT(ar); @@ -621,9 +708,6 @@ namespace plain_wallet return res; } - - - std::string try_pull_result(uint64_t job_id) { auto inst_ptr = std::atomic_load(&ginstance_ptr); diff --git a/src/wallet/plain_wallet_api_defs.h b/src/wallet/plain_wallet_api_defs.h index 9273d524..613227d0 100644 --- a/src/wallet/plain_wallet_api_defs.h +++ b/src/wallet/plain_wallet_api_defs.h @@ -47,4 +47,19 @@ namespace plain_wallet END_KV_SERIALIZE_MAP() }; + struct configure_object + { + bool postponed_run_wallet = false; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(postponed_run_wallet) + END_KV_SERIALIZE_MAP() + }; + struct configure_response + { + std::string status; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + } // namespace tools diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f7078763..5ab899dd 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -38,7 +38,7 @@ using namespace epee; #endif #ifndef DISABLE_TOR - #include "common/tor_helper.h" +#include "common/tor_helper.h" #endif #include "storages/levin_abstract_invoke2.h" @@ -69,7 +69,6 @@ namespace tools { wallet2::wallet2() : m_stop(false) - , m_wcallback(new i_wallet2_callback()) //stub , m_core_proxy(new default_http_core_proxy()) , m_upper_transaction_size_limit(0) , m_fake_outputs_count(0) @@ -129,7 +128,7 @@ namespace tools //---------------------------------------------------------------------------------------------------- std::string wallet2::transfer_flags_to_str(uint32_t flags) { - std::string result(7, ' '); + std::string result(8, ' '); if (flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT) result[0] = 's'; if (flags & WALLET_TRANSFER_DETAIL_FLAG_BLOCKED) @@ -142,8 +141,11 @@ std::string wallet2::transfer_flags_to_str(uint32_t flags) result[4] = 'c'; if (flags & WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM) result[5] = 'h'; + if (flags & WALLET_TRANSFER_DETAIL_CONCISE_MODE_PRESERVE) + result[6] = 'p'; if (flags & WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION) - result[6] = 'a'; + result[7] = 'a'; + return result; } //---------------------------------------------------------------------------------------------------- @@ -180,11 +182,11 @@ bool wallet2::set_core_proxy(const std::shared_ptr& proxy) //---------------------------------------------------------------------------------------------------- void wallet2::set_defragmentation_tx_settings(bool enabled, uint64_t min_outs, uint64_t max_outs, uint64_t max_allowed_amount, size_t decoys_count) { - m_defragmentation_tx_enabled = enabled; - m_min_utxo_count_for_defragmentation_tx = min_outs; - m_max_utxo_count_for_defragmentation_tx = max_outs; - m_max_allowed_output_amount_for_defragmentation_tx = max_allowed_amount; - m_decoys_count_for_defragmentation_tx = decoys_count; + m_defragmentation_tx_enabled = enabled; + m_min_utxo_count_for_defragmentation_tx = min_outs; + m_max_utxo_count_for_defragmentation_tx = max_outs; + m_max_allowed_output_amount_for_defragmentation_tx = max_allowed_amount; + m_decoys_count_for_defragmentation_tx = decoys_count; if (enabled) { WLT_LOG_L0("Defragmentation tx creation is enabled, settings: min outs: " << min_outs << ", max outs: " << max_outs << ", max amount: " << print_money_brief(max_allowed_amount) << @@ -208,26 +210,26 @@ bool wallet2::get_transfer_info_by_key_image(const crypto::key_image& ki, transf { return false; } - THROW_IF_FALSE_WALLET_EX(it->second < m_transfers.size(), error::wallet_internal_error, "wrong out in transaction: internal index"); - td = m_transfers[it->second]; + //THROW_IF_FALSE_WALLET_EX(it->second < m_transfers.size(), error::wallet_internal_error, "wrong out in transaction: internal index"); + td = m_transfers.at(it->second); i = it->second; return true; } //---------------------------------------------------------------------------------------------------- bool wallet2::get_transfer_info_by_index(size_t i, transfer_details& td) { - WLT_CHECK_AND_ASSERT_MES(i < m_transfers.size(), false, "wrong out in transaction: internal index, m_transfers.size()=" << m_transfers.size()); - td = m_transfers[i]; + //WLT_CHECK_AND_ASSERT_MES(i < m_transfers.size(), false, "wrong out in transaction: internal index, m_transfers.size()=" << m_transfers.size()); + td = m_transfers.at(i); return true; } //---------------------------------------------------------------------------------------------------- size_t wallet2::scan_for_collisions(std::unordered_map >& key_images) { - size_t count = 0; - for (size_t i = 0; i != m_transfers.size(); i++) + size_t count = 0; + for (const auto& tr : m_transfers) { - key_images[m_transfers[i].m_key_image].push_back(i); - if (key_images[m_transfers[i].m_key_image].size() > 1) + key_images[tr.second.m_key_image].push_back(tr.first); + if (key_images[tr.second.m_key_image].size() > 1) count++; } return count; @@ -238,9 +240,9 @@ size_t wallet2::fix_collisions() std::unordered_map > key_images; scan_for_collisions(key_images); size_t count = 0; - for (auto &coll_entry : key_images) + for (auto& coll_entry : key_images) { - if(coll_entry.second.size()<2) + if (coll_entry.second.size() < 2) continue; currency::COMMAND_RPC_CHECK_KEYIMAGES::request req_ki = AUTO_VAL_INIT(req_ki); @@ -252,10 +254,10 @@ size_t wallet2::fix_collisions() THROW_IF_FALSE_WALLET_INT_ERR_EX(*rsp_ki.images_stat.begin() != 0, "unable to get spent key image info for keyimage: " << coll_entry.first << "keyimages [0]=0"); - for (auto it = coll_entry.second.begin(); it!= coll_entry.second.end(); it++) + for (auto it = coll_entry.second.begin(); it != coll_entry.second.end(); it++) { - m_transfers[*it].m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; - m_transfers[*it].m_spent_height = *rsp_ki.images_stat.begin(); + m_transfers.at(*it).m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; + m_transfers.at(*it).m_spent_height = *rsp_ki.images_stat.begin(); WLT_LOG_L0("Fixed collision for key image " << coll_entry.first << " transfer " << count); count++; } @@ -271,13 +273,13 @@ size_t wallet2::scan_for_transaction_entries(const crypto::hash& tx_id, const cr for (auto it = m_transfers.begin(); it != m_transfers.end(); it++) { - if (check_ki && it->m_key_image == ki) + if (check_ki && it->second.m_key_image == ki) { - details.push_back(*it); + details.push_back(it->second); } - if (check_tx_id && get_transaction_hash(it->m_ptx_wallet_info->m_tx) == tx_id) + if (check_tx_id && get_transaction_hash(it->second.m_ptx_wallet_info->m_tx) == tx_id) { - details.push_back(*it); + details.push_back(it->second); } } return details.size(); @@ -394,8 +396,10 @@ const crypto::public_key& wallet2::out_get_pub_key(const currency::tx_out_v& out //---------------------------------------------------------------------------------------------------- void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_operation& ado, process_transaction_context& ptc) { - auto print_ado_owner = [ado](std::ostream& o){ - ado.descriptor.owner_eth_pub_key.has_value() ? o << ado.descriptor.owner_eth_pub_key.value() << " (ETH)" : o << ado.descriptor.owner; + auto print_ado_owner = [ado](/*std::ostream& o*/) { // temporary reverted to boring std::string, until operator<<(std::ostream& o, invocable_t callee) is fixed for C++17/Android + std::stringstream o; + if (ado.opt_descriptor.has_value()) { ado.opt_descriptor->owner_eth_pub_key.has_value() ? o << ado.opt_descriptor->owner_eth_pub_key.value() << " (ETH)" : o << ado.opt_descriptor->owner; } + return o.str(); }; do @@ -406,70 +410,77 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) { + + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ado.opt_descriptor.has_value(), "ado. missing opt_descriptor value at ASSET_DESCRIPTOR_OPERATION_REGISTER"); // Add an asset to ownership list if either: // 1) we're the owner of the asset; // or // 2) we spent native coins in the tx (i.e. we sent it) AND it registers an asset with third-party ownership. - if (ado.descriptor.owner != m_account.get_public_address().spend_public_key && - (!ado.descriptor.owner_eth_pub_key.has_value() || !ptc.spent_own_native_inputs)) + if (ado.opt_descriptor->owner != m_account.get_public_address().spend_public_key && + (!ado.opt_descriptor->owner_eth_pub_key.has_value() || !ptc.spent_own_native_inputs)) break; 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]; - epee::misc_utils::cast_assign_a_to_b(ado.descriptor, asset_context); + epee::misc_utils::cast_assign_a_to_b(*ado.opt_descriptor, asset_context); std::stringstream ss; ss << "New Asset Registered:" << ENDL << "asset id: " << asset_id - << ENDL << "Owner: " << print_ado_owner + << ENDL << "Owner: " << print_ado_owner() << ENDL << "Name: " << asset_context.full_name << ENDL << "Ticker: " << asset_context.ticker << ENDL << "Total Max Supply: " << print_asset_money(asset_context.total_max_supply, asset_context.decimal_point) << ENDL << "Current Supply: " << print_asset_money(asset_context.current_supply, asset_context.decimal_point) << ENDL << "Decimal Point: " << (int)asset_context.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()); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(i_wallet2_callback::ms_yellow, ss.str()); } else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) { - auto it = m_own_asset_descriptors.find(asset_id); - if (it == m_own_asset_descriptors.end()) - break; + // do nothing on emit/burn + // + // + //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 }); - epee::misc_utils::cast_assign_a_to_b(ado.descriptor, it->second); + //add_rollback_event(ptc.height, asset_update_event{ it->first, it->second }); + //epee::misc_utils::cast_assign_a_to_b(ado.opt_descriptor, it->second); } - else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE ) + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) { + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ado.opt_descriptor.has_value(), "ado. missing opt_descriptor value at ASSET_DESCRIPTOR_OPERATION_UPDATE"); + auto it = m_own_asset_descriptors.find(asset_id); if (it == m_own_asset_descriptors.end()) { - if (ado.descriptor.owner == m_account.get_public_address().spend_public_key) + if (ado.opt_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]; - epee::misc_utils::cast_assign_a_to_b(ado.descriptor, asset_context); + epee::misc_utils::cast_assign_a_to_b(*ado.opt_descriptor, asset_context); 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: " << (int)ado.descriptor.decimal_point; + << ENDL << "Name: " << ado.opt_descriptor->full_name + << ENDL << "Ticker: " << ado.opt_descriptor->ticker + << ENDL << "Total Max Supply: " << print_asset_money(ado.opt_descriptor->total_max_supply, ado.opt_descriptor->decimal_point) + << ENDL << "Current Supply: " << print_asset_money(ado.opt_descriptor->current_supply, ado.opt_descriptor->decimal_point) + << ENDL << "Decimal Point: " << (int)ado.opt_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()); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(i_wallet2_callback::ms_yellow, ss.str()); } else { @@ -480,7 +491,7 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op else { // check our ownership status: we lost it if the asset has new non-null owner (null means a third-party ownership, and in such a case we retain it in the own list whatever happens) - if (ado.descriptor.owner != null_pkey && ado.descriptor.owner != m_account.get_public_address().spend_public_key) + if (ado.opt_descriptor->owner != null_pkey && ado.opt_descriptor->owner != m_account.get_public_address().spend_public_key) { //ownership of the asset had been transfered add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second }); @@ -489,23 +500,23 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op std::stringstream ss; ss << "Asset ownership lost:" << ENDL << "asset id: " << asset_id - << ENDL << "New owner: " << print_ado_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: " << (int)ado.descriptor.decimal_point; + << ENDL << "New owner: " << print_ado_owner() + << ENDL << "Name: " << ado.opt_descriptor->full_name + << ENDL << "Ticker: " << ado.opt_descriptor->ticker + << ENDL << "Total Max Supply: " << print_asset_money(ado.opt_descriptor->total_max_supply, ado.opt_descriptor->decimal_point) + << ENDL << "Current Supply: " << print_asset_money(ado.opt_descriptor->current_supply, ado.opt_descriptor->decimal_point) + << ENDL << "Decimal Point: " << (int)ado.opt_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()); + if (auto wcb = m_wcallback.lock()) + wcb->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 }); - epee::misc_utils::cast_assign_a_to_b(ado.descriptor, it->second); + epee::misc_utils::cast_assign_a_to_b(*ado.opt_descriptor, it->second); } } } @@ -598,7 +609,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } } - for(auto& in : tx.vin) + for (auto& in : tx.vin) { ptc.sub_i = 0; VARIANT_SWITCH_BEGIN(in); @@ -640,13 +651,13 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t auto it = m_active_htlcs.find(std::make_pair(in_htlc.amount, boost::get(in_htlc.key_offsets[0]))); if (it != m_active_htlcs.end()) { - transfer_details& td = m_transfers[it->second]; + transfer_details& td = m_transfers.at(it->second); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.m_ptx_wallet_info->m_tx.vout.size() > td.m_internal_output_index, "Internal error: wrong td.m_internal_output_index: " << td.m_internal_output_index); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].type() == typeid(tx_out_bare), "Internal error: wrong output type: " << td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].type().name()); const boost::typeindex::type_info& ti = boost::get(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]).target.type(); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(ti == typeid(txout_htlc), "Internal error: wrong type of output's target: " << ti.name()); //input spend active htlc - m_transfers[it->second].m_spent_height = height; + m_transfers.at(it->second).m_spent_height = height; transfer_details_extra_option_htlc_info& tdeohi = get_or_add_field_to_variant_vector(td.varian_options); tdeohi.origin = in_htlc.hltc_origin; tdeohi.redeem_tx_id = ptc.tx_hash(); @@ -687,7 +698,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t pwallet_info->m_block_timestamp = b.timestamp; if (is_auditable()) - { + { WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(pglobal_indexes && pglobal_indexes->size() == tx.vout.size(), "wrong pglobal_indexes = " << pglobal_indexes << ""); } std::vector outputs_index_local; @@ -705,7 +716,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t pglobal_indexes = &outputs_index_local; } } - + for (size_t i_in_outs = 0; i_in_outs != outs.size(); i_in_outs++) { const wallet_out_info& out = outs[i_in_outs]; @@ -713,10 +724,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(o < tx.vout.size(), "wrong out in transaction: internal index: " << o << ", tx.vout.size(): " << tx.vout.size()); { const currency::tx_out_v& out_v = tx.vout[o]; - bool out_type_zc = out_is_zc(out_v); - bool out_type_to_key = out_is_to_key(out_v); - bool out_type_htlc = out_is_to_htlc(out_v); - bool out_type_multisig = out_is_multisig(out_v); + bool out_type_zc = out_is_zc(out_v); + bool out_type_to_key = out_is_to_key(out_v); + bool out_type_htlc = out_is_to_htlc(out_v); + bool out_type_multisig = out_is_multisig(out_v); if (out_type_zc || out_type_to_key || out_type_htlc) { @@ -771,8 +782,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t // 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]; + //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.at(it->second); std::stringstream ss; ss << "tx " << ptc.tx_hash() << " @ block " << height << " has output #" << o << " with amount " << out.amount; @@ -781,8 +792,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t 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()); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(i_wallet2_callback::ms_yellow, ss.str()); //if (out.is_native_coin()) //{ //WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount); @@ -803,8 +814,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t ss << " with amount " << print_money_brief(out.amount) << " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)mix_attr << ". Output is IGNORED."; WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0); - if (m_wcallback) - m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str()); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(i_wallet2_callback::ms_red, ss.str()); //if (out.is_native_coin()) //{ //WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(sum_of_native_outs >= out.amount, "sum_of_native_outs: " << sum_of_native_outs << ", out.amount:" << out.amount); @@ -813,10 +824,10 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t continue; // skip the output } - ptc.employed_entries.receive.push_back(wallet_public::employed_tx_entry{ o , out.amount , out.asset_id}); - - m_transfers.push_back(boost::value_initialized()); - transfer_details& td = m_transfers.back(); + ptc.employed_entries.receive.push_back(wallet_public::employed_tx_entry{ o , out.amount , out.asset_id }); + uint64_t new_index = m_transfers.empty() ? 0 : (--m_transfers.end())->first+1; + auto rsp = m_transfers.insert(std::make_pair(new_index, boost::value_initialized())); + transfer_details& td = rsp.first->second; td.m_ptx_wallet_info = pwallet_info; td.m_internal_output_index = o; td.m_key_image = ki; @@ -843,18 +854,18 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER; } } - + if (out_type_zc) { td.m_zc_info_ptr.reset(new transfer_details_base::ZC_out_info(out.amount_blinding_mask, out.asset_id_blinding_mask, out.asset_id)); } - size_t transfer_index = m_transfers.size() - 1; + size_t transfer_index = new_index; if (out_type_htlc) { const currency::txout_htlc& hltc = out_get_htlc(out_v); //mark this as spent - td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; + td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT|WALLET_TRANSFER_DETAIL_CONCISE_MODE_PRESERVE; //create entry for htlc input htlc_expiration_trigger het = AUTO_VAL_INIT(het); het.is_wallet_owns_redeem = (out_key == hltc.pkey_redeem) ? true : false; @@ -923,7 +934,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } else if (out_type_htlc) { - WLT_LOG_L0("Detected HTLC[" << (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? "REDEEM" : "REFUND") << "], transfer #" << transfer_index << ", amount: " << print_money(td.amount()) << ", with tx: " << ptc.tx_hash() << ", at height " << height); + WLT_LOG_L0("Detected HTLC[" << (td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? "REDEEM" : "REFUND") << "], transfer #" << transfer_index << ", amount: " << print_money(td.amount()) << ", with tx: " << ptc.tx_hash() << ", at height " << height); } } else if (out_type_multisig) @@ -944,7 +955,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t } } - + //do final calculations bool has_in_transfers = false; @@ -963,7 +974,9 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t //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)) + if (pado && (ptc.employed_entries.receive.size() || ptc.employed_entries.spent.size() || (pado->opt_descriptor.has_value() && pado->opt_descriptor->owner == m_account.get_public_address().spend_public_key) || + (pado->opt_asset_id.has_value() && m_own_asset_descriptors.count(pado->opt_asset_id.value())) + )) { //check if there are asset_registration that belong to this wallet process_ado_in_new_transaction(*pado, ptc); @@ -979,7 +992,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t if (ptc.sum_of_own_native_inputs) {//this actually is transfer transaction, notify about spend if (ptc.sum_of_own_native_inputs > sum_of_native_outs) - {//usual transfer + {//usual transfer handle_money_spent2(b, tx, ptc.sum_of_own_native_inputs - (sum_of_native_outs + get_tx_fee(tx)), ptc.mtd, recipients, remote_aliases); } else @@ -1033,7 +1046,7 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i account_public_address sender_address = AUTO_VAL_INIT(sender_address); wti.show_sender = handle_2_alternative_types_in_variant_container(decrypted_att, [&](const tx_payer& p) { sender_address = p.acc_addr; return false; /* <- continue? */ }); if (wti.show_sender) - if(!wti.remote_addresses.size()) + if (!wti.remote_addresses.size()) wti.remote_addresses.push_back(currency::get_account_address_as_str(sender_address)); } else @@ -1049,7 +1062,7 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i wti.remote_addresses.push_back(addr_str); LOG_PRINT_YELLOW("prepare_wti_decrypted_attachments, income=false, rem. addr = " << addr_str, LOG_LEVEL_0); return true; // continue iterating through the container - }); + }); } } @@ -1071,10 +1084,10 @@ void wallet2::resend_unconfirmed() if (!req.txs_as_hex.size()) return; - + bool r = m_core_proxy->call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(req, res); WLT_CHECK_AND_ASSERT_MES(r, void(), "wrong result at call_COMMAND_RPC_FORCE_RELAY_RAW_TXS"); - WLT_CHECK_AND_ASSERT_MES(res.status == API_RETURN_CODE_OK, void(), "wrong result at call_COMMAND_RPC_FORCE_RELAY_RAW_TXS: status != OK, status=" << res.status); + WLT_CHECK_AND_ASSERT_MES(res.status == API_RETURN_CODE_OK, void(), "wrong result at call_COMMAND_RPC_FORCE_RELAY_RAW_TXS: status != OK, status=" << res.status); WLT_LOG_GREEN("Relayed " << req.txs_as_hex.size() << " txs", LOG_LEVEL_0); } @@ -1127,10 +1140,10 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept //prepare templates to let buyer release or burn escrow bc_services::escrow_relese_templates_body artb = AUTO_VAL_INIT(artb); - build_escrow_release_templates(contract_id, + build_escrow_release_templates(contract_id, left_for_fee_in_multisig, artb.tx_normal_template, - artb.tx_burn_template, + artb.tx_burn_template, contr_it->second.private_detailes); @@ -1200,7 +1213,7 @@ void wallet2::finish_contract(const crypto::hash& contract_id, const std::string } else { - THROW_IF_FALSE_WALLET_INT_ERR_EX(false, "Unknow release_type = " << release_type); + THROW_IF_FALSE_WALLET_INT_ERR_EX(false, "Unknow release_type = " << release_type); } bool is_input_fully_signed = false; @@ -1243,7 +1256,7 @@ void wallet2::accept_cancel_contract(const crypto::hash& contract_id, currency:: send_transaction_to_network(tx); TIME_MEASURE_FINISH_MS(timing3); if (timing1 + timing2 + timing1 > 500) - WLT_LOG_RED("[wallet2::accept_cancel_contract] LOW PERFORMANCE: " << timing1 << "," << timing2 << "," << timing1, LOG_LEVEL_0); + WLT_LOG_RED("[wallet2::accept_cancel_contract] LOW PERFORMANCE: " << timing1 << "," << timing2 << "," << timing1, LOG_LEVEL_0); if (p_cancellation_acceptance_tx != nullptr) *p_cancellation_acceptance_tx = tx; @@ -1255,7 +1268,7 @@ void wallet2::request_cancel_contract(const crypto::hash& contract_id, uint64_t THROW_IF_FALSE_WALLET_INT_ERR_EX(contr_it != m_contracts.end(), "Unknow contract id: " << contract_id); THROW_IF_FALSE_WALLET_INT_ERR_EX(contr_it->second.is_a, "contr_it->second.is_a supposed to be true at request_cancel_contract"); - THROW_IF_FALSE_WALLET_INT_ERR_EX(contr_it->second.state == tools::wallet_public::escrow_contract_details_basic::contract_accepted + THROW_IF_FALSE_WALLET_INT_ERR_EX(contr_it->second.state == tools::wallet_public::escrow_contract_details_basic::contract_accepted || contr_it->second.state == tools::wallet_public::escrow_contract_details_basic::contract_cancel_proposal_sent, "incorrect contract state at request_cancel_contract(): " << tools::wallet_public::get_escrow_contract_state_name(contr_it->second.state) << ", expected states: contract_accepted (" << tools::wallet_public::escrow_contract_details_basic::contract_accepted << "), " << "contract_cancel_proposal_sent (" << tools::wallet_public::escrow_contract_details_basic::contract_cancel_proposal_sent << ")"); @@ -1314,11 +1327,11 @@ void wallet2::scan_tx_to_key_inputs(std::vector& found_transfers, cons { if (in.type() == typeid(currency::txin_to_key)) { - + auto it = m_key_images.find(boost::get(in).k_image); if (it != m_key_images.end()) found_transfers.push_back(it->second); - } + } } } //----------------------------------------------------------------------------------------------------- @@ -1326,7 +1339,7 @@ void wallet2::change_contract_state(wallet_public::escrow_contract_details_basic { WLT_LOG_YELLOW("escrow contract STATE CHANGE (" << (contract.is_a ? "A," : "B,") << contract_id << " via tx " << get_transaction_hash(wti.tx) << ", height: " << wti.height << ") : " << wallet_public::get_escrow_contract_state_name(contract.state) << " -> " << wallet_public::get_escrow_contract_state_name(new_state), LOG_LEVEL_1); - + contract.state = new_state; contract.height = wti.height; // update height of last state change } @@ -1335,7 +1348,7 @@ void wallet2::change_contract_state(wallet_public::escrow_contract_details_basic { WLT_LOG_YELLOW("escrow contract STATE CHANGE (" << (contract.is_a ? "A," : "B,") << contract_id << " " << reason << ") : " << wallet_public::get_escrow_contract_state_name(contract.state) << " -> " << wallet_public::get_escrow_contract_state_name(new_state), LOG_LEVEL_1); - + contract.state = new_state; } //----------------------------------------------------------------------------------------------------- @@ -1343,8 +1356,8 @@ void from_outs_to_received_items(const std::vector& o { for (const auto& item : outs) { - if(!out_is_multisig(tx.vout[item.index])) - received.push_back(tools::payment_details_subtransfer{ item.asset_id, item.amount}); + if (!out_is_multisig(tx.vout[item.index])) + received.push_back(tools::payment_details_subtransfer{ item.asset_id, item.amount }); } } //----------------------------------------------------------------------------------------------------- @@ -1369,7 +1382,7 @@ bool wallet2::handle_proposal(wallet_public::wallet_transfer_info& wti, const bc wti.contract.resize(1); static_cast(wti.contract.back()) = ed; wti.contract.back().contract_id = ms_id; - + //correct fee in case if it "B", cz fee is paid by "A" if (!ed.is_a) wti.fee = 0; @@ -1411,7 +1424,7 @@ bool wallet2::handle_release_contract(wallet_public::wallet_transfer_info& wti, { change_contract_state(it->second, wallet_public::escrow_contract_details_basic::contract_released_burned, ms_id, wti); wallet_public::wallet_sub_transfer_info* subptr = nullptr; - for (auto& s: wti.subtransfers) + for (auto& s : wti.subtransfers) { if (s.asset_id == currency::native_coin_asset_id) subptr = &s; @@ -1518,7 +1531,7 @@ bool wallet2::handle_cancel_proposal(wallet_public::wallet_transfer_info& wti, c WLT_LOG_RED("handle_cancel_proposal for contract (" << (it->second.is_a ? "A," : "B,") << contract_id << " via tx " << get_transaction_hash(wti.tx) << ", height: " << wti.height << ") : " << ENDL << "incorrect state " << wallet_public::get_escrow_contract_state_name(it->second.state) << ", while 'contract_accepted' or 'contract_cancel_proposal_sent' was expected -- decline cancel proposal", LOG_LEVEL_1); } - + return false; } //----------------------------------------------------------------------------------------------------- @@ -1555,9 +1568,9 @@ bool wallet2::process_contract_info(wallet_public::wallet_transfer_info& wti, co } else if ( - sa.instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL || - sa.instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_CANCEL || - sa.instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN + sa.instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL || + sa.instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_CANCEL || + sa.instruction == BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_BURN ) { handle_release_contract(wti, sa.instruction); @@ -1604,7 +1617,7 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces //escrow, and decryption should be processed as income flag //let's assume that the one who pays for tx fee is sender of tx - bool decrypt_attachment_as_income = !(tx_process_context.total_balance_change.count(currency::native_coin_asset_id) && tx_process_context.total_balance_change.at(currency::native_coin_asset_id) < 0 ); + bool decrypt_attachment_as_income = !(tx_process_context.total_balance_change.count(currency::native_coin_asset_id) && tx_process_context.total_balance_change.at(currency::native_coin_asset_id) < 0); std::vector decrypted_att; bool has_zero_input_as_spent = false; for (const auto& item : tx_process_context.employed_entries.spent) @@ -1615,13 +1628,13 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces break; } } - + if (wti.tx_type == GUI_TX_TYPE_ESCROW_TRANSFER && !has_zero_input_as_spent) decrypt_attachment_as_income = true; decrypt_payload_items(decrypt_attachment_as_income, wti.tx, m_account.get_keys(), decrypted_att); - if ((is_watch_only() && !decrypt_attachment_as_income)|| (wti.height > 638000 && !have_type_in_variant_container(decrypted_att))) + if ((is_watch_only() && !decrypt_attachment_as_income) || (wti.height > 638000 && !have_type_in_variant_container(decrypted_att))) { remove_field_of_type_from_extra(decrypted_att); remove_field_of_type_from_extra(decrypted_att); @@ -1676,44 +1689,10 @@ void wallet2::rise_on_transfer2(const wallet_public::wallet_transfer_info& wti) std::list balances; uint64_t mined_balance = 0; this->balance(balances, mined_balance); - m_wcallback->on_transfer2(wti, balances, mined_balance); - // second call for legacy callback handlers - //m_wcallback->on_transfer2(wti, balances, mined_balance); + if (auto wcb = m_wcallback.lock()) + wcb->on_transfer2(wti, balances, mined_balance); } //---------------------------------------------------------------------------------------------------- -/* -void wallet2::handle_money_spent2(const currency::block& b, - const currency::transaction& in_tx, - uint64_t amount, - const money_transfer2_details& td, - const std::vector& recipients, - const std::vector& remote_aliases) -{ - m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); - wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); - wti.is_income = false; - - wti.remote_addresses = recipients; - wti.remote_aliases = remote_aliases; - prepare_wti(wti, get_block_height(b), get_block_datetime(b), in_tx, amount, td); - WLT_LOG_L1("[MONEY SPENT]: " << epee::serialization::store_t_to_json(wti)); - rise_on_transfer2(wti); -} -//---------------------------------------------------------------------------------------------------- -void wallet2::handle_money_received2(const currency::block& b, const currency::transaction& tx, uint64_t amount, const money_transfer2_details& td) -{ - //decrypt attachments - m_transfer_history.push_back(AUTO_VAL_INIT(wallet_public::wallet_transfer_info())); - wallet_public::wallet_transfer_info& wti = m_transfer_history.back(); - wti.is_income = true; - // TODO @#@# this function is only able to handle native coins atm, consider changing -- sowle - wti.asset_id = native_coin_asset_id; - prepare_wti(wti, get_block_height(b), get_block_datetime(b), tx, amount, td); - WLT_LOG_L1("[MONEY RECEIVED]: " << epee::serialization::store_t_to_json(wti)); - rise_on_transfer2(wti); -} -*/ - //---------------------------------------------------------------------------------------------------- void wallet2::load_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context) { wti.remote_addresses = tx_process_context.recipients; @@ -1780,7 +1759,7 @@ void wallet2::unprocess_htlc_triggers_on_block_removed(uint64_t height) auto pair_of_it = m_htlcs.equal_range(height); for (auto it = pair_of_it.first; it != pair_of_it.second; it++) { - auto& tr = m_transfers[it->second.transfer_index]; + auto& tr = m_transfers.at(it->second.transfer_index); //found contract that supposed to be re-activated and set to active if (it->second.is_wallet_owns_redeem) { @@ -1805,7 +1784,7 @@ void wallet2::unprocess_htlc_triggers_on_block_removed(uint64_t height) { LOG_ERROR("Error at putting back htlc: already exist?"); it_active_htlc->second = it->second.transfer_index; - + } else { @@ -1841,7 +1820,7 @@ void wallet2::process_htlc_triggers_on_block_added(uint64_t height) auto pair_of_it = m_htlcs.equal_range(height); for (auto it = pair_of_it.first; it != pair_of_it.second; it++) { - auto& tr = m_transfers[it->second.transfer_index]; + auto& tr = m_transfers.at(it->second.transfer_index); //found contract that supposed to be deactivated and set to innactive if (it->second.is_wallet_owns_redeem) { @@ -1855,8 +1834,8 @@ void wallet2::process_htlc_triggers_on_block_added(uint64_t height) tr.m_flags &= ~(WALLET_TRANSFER_DETAIL_FLAG_SPENT); //reset spent flag m_found_free_amounts.clear(); //reset free amounts cache tr.m_spent_height = 0; - } - + } + //reset cache m_found_free_amounts.clear(); @@ -1892,7 +1871,7 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre !(height == m_minimum_height || get_blockchain_current_size() <= 1), error::wallet_internal_error, "current_index=" + std::to_string(height) + ", get_blockchain_current_height()=" + std::to_string(get_blockchain_current_size())); - + //optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup @@ -1910,21 +1889,22 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre TIME_MEASURE_START(txs_handle_time); size_t count = 0; - for(const auto& tx_entry: bche.txs_ptr) + for (const auto& tx_entry : bche.txs_ptr) { if (b.tx_hashes.size() < count || currency::get_transaction_hash(tx_entry->tx) != b.tx_hashes[count]) { - LOG_ERROR("Found tx order fail in process_new_blockchain_entry: count=" << count + LOG_ERROR("Found tx order fail in process_new_blockchain_entry: count=" << count << ", b.tx_hashes.size() = " << b.tx_hashes.size() << ", tx real id: " << currency::get_transaction_hash(tx_entry->tx) << ", bl_id: " << bl_id); } process_new_transaction(tx_entry->tx, height, b, &(tx_entry->m_global_output_indexes)); count++; } TIME_MEASURE_FINISH(txs_handle_time); - WLT_LOG_L3("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms"); - }else + WLT_LOG_L3("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time << ")ms"); + } + else { - WLT_LOG_L3( "Skipped block by timestamp, height: " << height << ", block time " << b.timestamp << ", account time " << m_account.get_createtime()); + WLT_LOG_L3("Skipped block by timestamp, height: " << height << ", block time " << b.timestamp << ", account time " << m_account.get_createtime()); } m_chain.push_new_block_id(bl_id, height); //m_blockchain.push_back(bl_id); m_last_bc_timestamp = b.timestamp; @@ -1933,7 +1913,8 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre process_htlc_triggers_on_block_added(height); - m_wcallback->on_new_block(height, b); + if (auto wcb = m_wcallback.lock()) + wcb->on_new_block(height, b); } //---------------------------------------------------------------------------------------------------- @@ -1974,7 +1955,7 @@ void wallet2::set_minimum_height(uint64_t h) //---------------------------------------------------------------------------------------------------- uint64_t wallet2::get_wallet_minimum_height() { - + if (m_minimum_height != WALLET_MINIMUM_HEIGHT_UNSET_CONST) return m_minimum_height; @@ -1988,7 +1969,7 @@ uint64_t wallet2::get_wallet_minimum_height() return res.h; } //---------------------------------------------------------------------------------------------------- -void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop) +void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop, bool& full_reset_needed) { blocks_added = 0; currency::COMMAND_RPC_GET_BLOCKS_DIRECT::request req = AUTO_VAL_INIT(req); @@ -2039,12 +2020,33 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic& stop) "wrong daemon response: m_start_height=" + std::to_string(res.start_height) + " not less than local blockchain size=" + std::to_string(get_blockchain_current_size())); - handle_pulled_blocks(blocks_added, stop, res); + try + { + handle_pulled_blocks(blocks_added, stop, res, full_reset_needed); + } + catch (const tools::error::wallet_error_resync_needed& /*v*/) + { + full_reset_needed = true; + m_full_resync_requested_at_h = get_blockchain_current_size() - blocks_added; + } + + if (full_reset_needed) + { + //back up m_unconfirmed_txs + //back up std::unordered_map m_tx_keys; + unconfirmed_txs_container tmp_unconfirmed = m_unconfirmed_txs; + tx_secrete_keys_container tmp_secrete_keys = m_tx_keys; + crypto::hash genesis = m_chain.get_genesis(); + reset_all(); + m_chain.set_genesis(genesis); + m_unconfirmed_txs = tmp_unconfirmed; + m_tx_keys = tmp_secrete_keys; + } } //---------------------------------------------------------------------------------------------------- -void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, - currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& res) +void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, + currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& res, bool& wallet_reset_needed) { size_t current_index = res.start_height; m_last_known_daemon_height = res.current_height; @@ -2053,7 +2055,7 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop { const currency::block& genesis = res.blocks.front().block_ptr->bl; THROW_IF_TRUE_WALLET_EX(get_block_height(genesis) != 0, error::wallet_internal_error, "first block expected to be genesis"); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(res.blocks.front().coinbase_ptr, "Unexpected empty coinbase"); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(res.blocks.front().coinbase_ptr, "Unexpected empty coinbase"); process_genesis_if_needed(genesis, &(res.blocks.front().coinbase_ptr->m_global_output_indexes)); res.blocks.pop_front(); ++current_index; @@ -2061,7 +2063,7 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop } uint64_t last_matched_index = 0; - for(const auto& bl_entry: res.blocks) + for (const auto& bl_entry : res.blocks) { if (stop) break; @@ -2092,14 +2094,14 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop //regular block handling //self check WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(been_matched_block, - "internal error: been_matched_block == false on process_new_blockchain_entry, bl_id" << bl_id << "h=" << height - << " (start_height=" + std::to_string(res.start_height) + ")"); + "internal error: been_matched_block == false on process_new_blockchain_entry, bl_id" << bl_id << "h=" << height + << " (start_height=" + std::to_string(res.start_height) + ")"); process_new_blockchain_entry(bl, bl_entry, bl_id, current_index); ++blocks_added; } else - { + { //checking if we need reorganize (might be just first matched block) bool block_found = false; bool block_matched = false; @@ -2127,7 +2129,13 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop } //TODO: take into account date of wallet creation //reorganize - detach_blockchain(last_matched_index+1); + if (m_concise_mode && m_chain.get_blockchain_current_size() - (last_matched_index) > m_wallet_concise_mode_max_reorg_blocks) + { + m_full_resync_requested_at_h = m_chain.get_blockchain_current_size() - (last_matched_index + 1); + wallet_reset_needed = true; + return; + } + detach_blockchain(last_matched_index + 1); process_new_blockchain_entry(bl, bl_entry, bl_id, height); ++blocks_added; } @@ -2140,7 +2148,8 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic& stop uint64_t next_percent = (100 * (current_index - m_height_of_start_sync)) / (res.current_height - m_height_of_start_sync); if (next_percent != m_last_sync_percent) { - m_wcallback->on_sync_progress(next_percent); + if (auto wcb = m_wcallback.lock()) + wcb->on_sync_progress(next_percent); m_last_sync_percent = next_percent; } } @@ -2160,7 +2169,7 @@ void wallet2::refresh() refresh(blocks_fetched); } //---------------------------------------------------------------------------------------------------- -void wallet2::refresh(size_t & blocks_fetched) +void wallet2::refresh(size_t& blocks_fetched) { bool received_money = false; m_stop = false; @@ -2178,7 +2187,7 @@ detail::split_strategy_id_t wallet2::get_current_split_strategy() { if (is_need_to_split_outputs()) return tools::detail::ssi_digit; - else + else return tools::detail::ssi_void; } // @@ -2241,7 +2250,7 @@ bool wallet2::has_related_alias_entry_unconfirmed(const currency::transaction& t if (tei.m_alias.m_alias.size()) { //have some check address involved - if (tei.m_alias.m_address.spend_public_key == m_account.get_keys().account_address.spend_public_key && + if (tei.m_alias.m_address.spend_public_key == m_account.get_keys().account_address.spend_public_key && tei.m_alias.m_address.view_public_key == m_account.get_keys().account_address.view_public_key) return true; @@ -2280,9 +2289,10 @@ bool wallet2::get_bare_unspent_outputs_stats(std::vector> buo_ids; // tx hash -> Bare Unspent Outs list - for(size_t tid = 0; tid != m_transfers.size(); ++tid) + for (const auto& tr : m_transfers) { - const auto& td = m_transfers[tid]; + uint64_t tid = tr.first; + const auto& td = m_transfers.at(tid); if (!td.is_zc() && td.is_spendable()) { buo_ids[td.tx_hash()].push_back(tid); @@ -2294,17 +2304,17 @@ bool wallet2::get_bare_unspent_outputs_stats(std::vector MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC) tids_grouped_by_txs.emplace_back(); - for(auto& tid : buo_el.second) + for (auto& tid : buo_el.second) { if (tids_grouped_by_txs.back().tids.size() >= MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC) tids_grouped_by_txs.emplace_back(); tids_grouped_by_txs.back().tids.push_back((uint64_t)tid); - tids_grouped_by_txs.back().total_amount += m_transfers[tid].m_amount; + tids_grouped_by_txs.back().total_amount += m_transfers.at(tid).m_amount; } } @@ -2313,21 +2323,22 @@ bool wallet2::get_bare_unspent_outputs_stats(std::vector usable_zc_outs_tids; // grouped by amount bool usable_zc_outs_tids_precalculated = false; - auto precalculate_usable_zc_outs_if_needed = [&](){ - if (usable_zc_outs_tids_precalculated) - return; - size_t decoys = is_auditable() ? 0 : m_core_runtime_config.hf4_minimum_mixins; - for(size_t tid = 0; tid != m_transfers.size(); ++tid) - { - auto& td = m_transfers[tid]; - if (td.is_zc() && td.is_native_coin() && is_transfer_ready_to_go(td, decoys)) - usable_zc_outs_tids.insert(std::make_pair(td.m_amount, tid)); - } - usable_zc_outs_tids_precalculated = true; + auto precalculate_usable_zc_outs_if_needed = [&]() { + if (usable_zc_outs_tids_precalculated) + return; + size_t decoys = is_auditable() ? 0 : m_core_runtime_config.hf4_minimum_mixins; + for (const auto& tr : m_transfers) + { + uint64_t tid = tr.first; + auto& td = m_transfers.at(tid); + if (td.is_zc() && td.is_native_coin() && is_transfer_ready_to_go(td, decoys)) + usable_zc_outs_tids.insert(std::make_pair(td.m_amount, tid)); + } + usable_zc_outs_tids_precalculated = true; }; std::unordered_set used_zc_outs; - for(auto it = tids_grouped_by_txs.begin(); it != tids_grouped_by_txs.end(); ) + for (auto it = tids_grouped_by_txs.begin(); it != tids_grouped_by_txs.end(); ) { auto& group = *it; if (group.total_amount < TX_MINIMUM_FEE) @@ -2337,7 +2348,7 @@ bool wallet2::get_bare_unspent_outputs_stats(std::vectorfirst >= min_required_amount, "jt->first=" << jt->first << ", min_required_amount=" << min_required_amount); if (used_zc_outs.count(jt->second) == 0) @@ -2377,7 +2388,7 @@ bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& bool send_to_network = true; size_t batch_index = 0; - for(const batch_of_bare_unspent_outs& group : tids_grouped_by_txs) + for (const batch_of_bare_unspent_outs& group : tids_grouped_by_txs) { currency::finalized_tx ftx{}; currency::finalize_tx_param ftp{}; @@ -2391,13 +2402,13 @@ bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& return false; } uint64_t fee = TX_DEFAULT_FEE; - std::vector destinations{tx_destination_entry(group.total_amount + group.additional_tid_amount - fee, target_address)}; - assets_selection_context needed_money_map{std::make_pair(native_coin_asset_id, selection_for_amount{group.total_amount + group.additional_tid_amount, group.total_amount + group.additional_tid_amount})}; + std::vector destinations{ tx_destination_entry(group.total_amount + group.additional_tid_amount - fee, target_address) }; + assets_selection_context needed_money_map{ std::make_pair(native_coin_asset_id, selection_for_amount{group.total_amount + group.additional_tid_amount, group.total_amount + group.additional_tid_amount}) }; try { prepare_tx_destinations(needed_money_map, get_current_split_strategy(), tx_dust_policy{}, destinations, 0 /* tx_flags */, ftp.prepared_destinations); } - catch(...) + catch (...) { on_tx_sent(batch_index, transaction{}, 0, 0, false, "destinations for tx couldn't be prepared"); LOG_PRINT_L0("prepare_tx_destinations failed, batch_index = " << batch_index); @@ -2410,13 +2421,13 @@ bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& finalize_transaction(ftp, ftx, send_to_network); on_tx_sent(batch_index, ftx.tx, group.total_amount + group.additional_tid_amount, fee, true, std::string()); } - catch(std::exception& e) + catch (std::exception& e) { clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception on sweep bare UTXO, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(ftx.tx))); on_tx_sent(batch_index, transaction{}, 0, 0, false, e.what()); return false; } - + ++batch_index; } @@ -2431,13 +2442,13 @@ bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& total_fee_spent = 0; total_bare_outs_sent = 0; auto on_tx_sent_callback = [&](size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err) { - if (sent_ok) - { - total_bare_outs_sent += count_type_in_variant_container(tx.vin); - ++total_txs_sent; - total_fee_spent += fee; - total_amount_sent += amount; - } + if (sent_ok) + { + total_bare_outs_sent += count_type_in_variant_container(tx.vin); + ++total_txs_sent; + total_fee_spent += fee; + total_amount_sent += amount; + } }; return sweep_bare_unspent_outputs(target_address, tids_grouped_by_txs, on_tx_sent_callback); @@ -2453,10 +2464,10 @@ uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet( return get_directly_spent_transfer_index_by_input_in_tracking_wallet(0, inzc.key_offsets); } //---------------------------------------------------------------------------------------------------- -uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet(uint64_t amount, const std::vector & key_offsets) +uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet(uint64_t amount, const std::vector& key_offsets) { WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(is_auditable() && is_watch_only(), "this is not an auditable-watch-only (tracking) wallet"); - + uint64_t tid = UINT64_MAX; // try to find a reference among own UTXOs @@ -2470,8 +2481,8 @@ uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet( if (it != m_amount_gindex_to_transfer_id.end()) { tid = it->second; - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tid < m_transfers.size(), "invalid tid: " << tid << ", ref from input with amount: " << amount << ", gindex: " << gindex); - auto& td = m_transfers[it->second]; + //WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(tid < m_transfers.size(), "invalid tid: " << tid << ", ref from input with amount: " << amount << ", gindex: " << gindex); + auto& td = m_transfers.at(it->second); if (key_offsets.size() != 1) { // own output was used in non-direct transaction @@ -2480,8 +2491,8 @@ uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet( std::stringstream ss; ss << "own transfer tid=" << tid << " tx=" << td.tx_hash() << " mix_attr=" << td.mix_attr() << ", is referenced by a transaction with mixins, ref from input with amount: " << amount << ", gindex: " << gindex; WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0); - if (m_wcallback) - m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str()); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(i_wallet2_callback::ms_yellow, ss.str()); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.mix_attr() != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX, ss.str()); // if mix_attr == 1 this should never happen (mixing in an output with mix_attr = 1) as the core must reject such txs // our own output has mix_attr != 1 for some reason (a sender did not set correct mix_attr e.g.) // but mixin count > 1 so we can't say it is spent for sure @@ -2514,7 +2525,7 @@ void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) //collect incomes for (auto& o : outs) { - if(out_is_multisig(tx.vout[o.index])) + if (out_is_multisig(tx.vout[o.index])) continue; ptc.total_balance_change[o.asset_id] += o.amount; @@ -2553,10 +2564,10 @@ void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) { // own output is being spent by this input //sum_of_spent_native_coin += intk.amount; - ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ i, m_transfers[tid].amount(), m_transfers[tid].get_asset_id() }); + ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ i, m_transfers.at(tid).amount(), m_transfers.at(tid).get_asset_id() }); spend_transfers.push_back(tid); - ptc.total_balance_change[currency::native_coin_asset_id] -= m_transfers[tid].amount(); - CHECK_AND_ASSERT_THROW_MES(m_transfers[tid].get_asset_id() == currency::native_coin_asset_id, "Unexpected asset id for native txin_to_key"); + ptc.total_balance_change[currency::native_coin_asset_id] -= m_transfers.at(tid).amount(); + CHECK_AND_ASSERT_THROW_MES(m_transfers.at(tid).get_asset_id() == currency::native_coin_asset_id, "Unexpected asset id for native txin_to_key"); } } else if (in.type() == typeid(currency::txin_zc_input)) @@ -2581,9 +2592,9 @@ void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) if (tid != UINT64_MAX) { - ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ i, m_transfers[tid].amount(), m_transfers[tid].get_asset_id() }); + ptc.employed_entries.spent.push_back(wallet_public::employed_tx_entry{ i, m_transfers.at(tid).amount(), m_transfers.at(tid).get_asset_id() }); spend_transfers.push_back(tid); - ptc.total_balance_change[m_transfers[tid].get_asset_id()] -= m_transfers[tid].amount(); + ptc.total_balance_change[m_transfers.at(tid).get_asset_id()] -= m_transfers.at(tid).amount(); } } else if (in.type() == typeid(currency::txin_multisig)) @@ -2641,14 +2652,14 @@ void wallet2::handle_unconfirmed_tx(process_transaction_context& ptc) prepare_wti(unconfirmed_wti, ptc); for (auto tr_index : spend_transfers) { - if (tr_index > m_transfers.size()) - { - WLT_LOG_ERROR("INTERNAL ERROR: tr_index " << tr_index << " more then m_transfers.size()=" << m_transfers.size()); - continue; - } - uint32_t flags_before = m_transfers[tr_index].m_flags; - m_transfers[tr_index].m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; - WLT_LOG_L1("wallet transfer #" << tr_index << " is marked as spent, flags: " << flags_before << " -> " << m_transfers[tr_index].m_flags << ", reason: UNCONFIRMED tx: " << ptc.tx_hash()); + //if (tr_index > m_transfers.size()) + //{ + // WLT_LOG_ERROR("INTERNAL ERROR: tr_index " << tr_index << " more then m_transfers.size()=" << m_transfers.size()); + // continue; + //} + uint32_t flags_before = m_transfers.at(tr_index).m_flags; + m_transfers.at(tr_index).m_flags |= WALLET_TRANSFER_DETAIL_FLAG_SPENT; + WLT_LOG_L1("wallet transfer #" << tr_index << " is marked as spent, flags: " << flags_before << " -> " << m_transfers.at(tr_index).m_flags << ", reason: UNCONFIRMED tx: " << ptc.tx_hash()); unconfirmed_wti.selected_indicies.push_back(tr_index); } rise_on_transfer2(unconfirmed_wti); @@ -2667,13 +2678,13 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) if (!r) throw error::no_connection_to_daemon(LOCATION_STR, "get_tx_pool"); THROW_IF_TRUE_WALLET_EX(res.status != API_RETURN_CODE_OK, error::get_blocks_error, res.status); - + //- @#@ ----- debug #ifdef _DEBUG std::stringstream ss; ss << "TXS FROM POOL: " << ENDL; - for (const auto &tx_blob : res.txs) + for (const auto& tx_blob : res.txs) { currency::transaction tx; bool r = parse_and_validate_tx_from_blob(tx_blob, tx); @@ -2683,7 +2694,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) ss << tx_hash << ENDL; } ss << "UNCONFIRMED TXS: " << ENDL; - for (const auto &tx_it : m_unconfirmed_in_transfers) + for (const auto& tx_it : m_unconfirmed_in_transfers) { ss << tx_it.first << ENDL; } @@ -2696,7 +2707,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) has_related_alias_in_unconfirmed = false; uint64_t tx_expiration_ts_median = res.tx_expiration_ts_median; //get_tx_expiration_median(); - for (const auto &tx_blob : res.txs) + for (const auto& tx_blob : res.txs) { currency::transaction tx; //money_transfer2_details td; @@ -2724,8 +2735,8 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) // IF NOT EXISTS IN unconfirmed_multisig_transfers_in_tx_pool AND EXISTS IN m_unconfirmed_multisig_transfers => EITHER became confirmed (added to the blockchain) OR removed from the pool for some other reason (clear spent flag if there's spent height == 0, means wasn't added to the blockchain) std::unordered_set unconfirmed_in_multisig_transfers; - for(auto& el : m_unconfirmed_in_transfers) - for(auto &in : el.second.vin) + for (auto& el : m_unconfirmed_in_transfers) + for (auto& in : el.second.vin) if (in.type() == typeid(txin_multisig)) unconfirmed_in_multisig_transfers.insert(boost::get(in).multisig_out_id); @@ -2739,7 +2750,7 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed) // Process unconfirmed tx dissapeared from the pool auto it = m_multisig_transfers.find(multisig_id); - if (it != m_multisig_transfers.end() && it->second.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT) + if (it != m_multisig_transfers.end() && it->second.m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT) { if (it->second.m_spent_height == 0) { @@ -2795,20 +2806,21 @@ bool wallet2::scan_not_compliant_unconfirmed_txs() //lookup all used transfer and update flags for (auto i : it->second.selected_indicies) { - if (i >= m_transfers.size()) + //if (i >= m_transfers.size()) + //{ + // WLT_LOG_ERROR("Wrong index '" << i << "' in 'selected_indicies', while m_transfers.size() = " << m_transfers.size()); + // continue; + //} + if (!m_transfers.at(i).m_spent_height) { - WLT_LOG_ERROR("Wrong index '" << i << "' in 'selected_indicies', while m_transfers.size() = " << m_transfers.size()); - continue; - } - if (!m_transfers[i].m_spent_height) - { - uint32_t flags_before = m_transfers[i].m_flags; - m_transfers[i].m_flags &= ~(WALLET_TRANSFER_DETAIL_FLAG_SPENT); // TODO: consider removing other blocking flags (e.g. for escrow tx) -- sowle - WLT_LOG_BLUE("mark transfer #" << i << " as unspent, flags: " << flags_before << " -> " << m_transfers[i].m_flags << ", reason: removing unconfirmed tx " << it->second.tx_hash, LOG_LEVEL_0); + uint32_t flags_before = m_transfers.at(i).m_flags; + m_transfers.at(i).m_flags &= ~(WALLET_TRANSFER_DETAIL_FLAG_SPENT); // TODO: consider removing other blocking flags (e.g. for escrow tx) -- sowle + WLT_LOG_BLUE("mark transfer #" << i << " as unspent, flags: " << flags_before << " -> " << m_transfers.at(i).m_flags << ", reason: removing unconfirmed tx " << it->second.tx_hash, LOG_LEVEL_0); } } //fire some event - m_wcallback->on_transfer_canceled(it->second); + if (auto wcb = m_wcallback.lock()) + wcb->on_transfer_canceled(it->second); m_unconfirmed_txs.erase(it++); } else @@ -2832,13 +2844,14 @@ bool wallet2::scan_not_compliant_unconfirmed_txs() } } - size_t sz = m_transfers.size(); - for (size_t i = 0; i != sz; i++) + + for (auto& tr : m_transfers) { - auto& t = m_transfers[i]; - - if (t.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT && !t.m_spent_height && !static_cast(t.m_flags&WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) - && !t.is_htlc()) + uint64_t i = tr.first; + auto& t = tr.second; + + if (t.m_flags & WALLET_TRANSFER_DETAIL_FLAG_SPENT && !t.m_spent_height && !static_cast(t.m_flags & WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION) + && !t.is_htlc()) { //check if there is unconfirmed for this transfer is no longer exist? if (!ki_in_unconfirmed.count((t.m_key_image))) @@ -2849,28 +2862,45 @@ bool wallet2::scan_not_compliant_unconfirmed_txs() } } } - + return true; } //---------------------------------------------------------------------------------------------------- -void wallet2::refresh(size_t & blocks_fetched, bool& received_money, std::atomic& stop) +void wallet2::refresh(size_t& blocks_fetched, bool& received_money, std::atomic& stop) { load_whitelisted_tokens_if_not_loaded(); + bool had_full_reset = false; received_money = false; blocks_fetched = 0; size_t added_blocks = 0; size_t try_count = 0; - crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash(m_transfers.back().m_ptx_wallet_info->m_tx) : null_hash; + size_t reset_count = 0; + crypto::hash last_tx_hash_id = m_transfers.size() ? get_transaction_hash((--m_transfers.end())->second.m_ptx_wallet_info->m_tx) : null_hash; m_height_of_start_sync = get_blockchain_current_size(); m_last_sync_percent = 0; while (!stop.load(std::memory_order_relaxed)) { try { - pull_blocks(added_blocks, stop); + bool full_reset_needed = false; + pull_blocks(added_blocks, stop, full_reset_needed); + if (full_reset_needed) + { + if (reset_count > 1) + { + WLT_LOG_L0("Intenral error: reset_count infinit loop catch"); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(tools::i_wallet2_callback::ms_red, "Internal error: reset_count infinite loop catch"); + return; + } + reset_count++; + m_height_of_start_sync = 0; + had_full_reset = true; + continue; + } blocks_fetched += added_blocks; - if(!added_blocks) + if (!added_blocks) break; } catch (error::no_connection_to_daemon&) @@ -2879,21 +2909,21 @@ void wallet2::refresh(size_t & blocks_fetched, bool& received_money, std::atomic if (++try_count > 3) return; WLT_LOG_L2("no connection to the daemon, wait and try pull_blocks again (try_count: " << try_count << ", blocks_fetched: " << blocks_fetched << ")"); - if (m_wcallback) - m_wcallback->on_message(tools::i_wallet2_callback::ms_red, "no connection to daemon"); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(tools::i_wallet2_callback::ms_red, "no connection to daemon"); std::this_thread::sleep_for(std::chrono::seconds(3)); } catch (const std::exception& e) { blocks_fetched += added_blocks; WLT_LOG_ERROR("refresh->pull_blocks failed, try_count: " << try_count << ", blocks_fetched: " << blocks_fetched << ", exception: " << e.what()); - if (m_wcallback) - m_wcallback->on_message(tools::i_wallet2_callback::ms_red, std::string("error on pulling blocks: ") + e.what()); + if (auto wcb = m_wcallback.lock()) + wcb->on_message(tools::i_wallet2_callback::ms_red, std::string("error on pulling blocks: ") + e.what()); return; } } - if(last_tx_hash_id != (m_transfers.size() ? get_transaction_hash(m_transfers.back().m_ptx_wallet_info->m_tx) : null_hash)) + if (last_tx_hash_id != (m_transfers.size() ? get_transaction_hash((--m_transfers.end())->second.m_ptx_wallet_info->m_tx) : null_hash)) received_money = true; if (blocks_fetched) @@ -2903,10 +2933,15 @@ void wallet2::refresh(size_t & blocks_fetched, bool& received_money, std::atomic uint64_t tx_expiration_ts_median = get_tx_expiration_median(); handle_expiration_list(tx_expiration_ts_median); handle_contract_expirations(tx_expiration_ts_median); - m_found_free_amounts.clear(); + truncate_wallet(); } - + if (had_full_reset) + { + blocks_fetched = get_blockchain_current_size() - m_full_resync_requested_at_h; + m_full_resync_requested_at_h = 0; + } + WLT_LOG("Refresh done, blocks received: " << blocks_fetched, blocks_fetched > 0 ? LOG_LEVEL_1 : LOG_LEVEL_2); } @@ -2919,7 +2954,7 @@ bool wallet2::handle_expiration_list(uint64_t tx_expiration_ts_median) { for (auto tr_ind : it->selected_transfers) { - auto &transfer = m_transfers[tr_ind]; + auto& transfer = m_transfers.at(tr_ind); if (!transfer.m_spent_height) { // Clear WALLET_TRANSFER_DETAIL_FLAG_BLOCKED and WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION flags only. @@ -2927,7 +2962,7 @@ bool wallet2::handle_expiration_list(uint64_t tx_expiration_ts_median) uint32_t flags_before = transfer.m_flags; transfer.m_flags &= ~(WALLET_TRANSFER_DETAIL_FLAG_BLOCKED); transfer.m_flags &= ~(WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION); - WLT_LOG_GREEN("Unlocked money from expiration_list: transfer #" << tr_ind << ", flags: " << flags_before << " -> " << transfer.m_flags << ", amount: " << print_money(transfer.amount()) << ", tx: " << + WLT_LOG_GREEN("Unlocked money from expiration_list: transfer #" << tr_ind << ", flags: " << flags_before << " -> " << transfer.m_flags << ", amount: " << print_money(transfer.amount()) << ", tx: " << (transfer.m_ptx_wallet_info != nullptr ? get_transaction_hash(transfer.m_ptx_wallet_info->m_tx) : null_hash), LOG_LEVEL_0); } @@ -2949,19 +2984,19 @@ void wallet2::handle_contract_expirations(uint64_t tx_expiration_ts_median) { switch (contract.second.state) { - case tools::wallet_public::escrow_contract_details_basic::contract_cancel_proposal_sent: - if (is_tx_expired(contract.second.cancel_body.tx_cancel_template, tx_expiration_ts_median)) - change_contract_state(contract.second, tools::wallet_public::escrow_contract_details_basic::contract_accepted, contract.first, "cancel proposal expiration"); - break; - case tools::wallet_public::escrow_contract_details_basic::contract_released_cancelled: - if (contract.second.height == 0 && is_tx_expired(contract.second.cancel_body.tx_cancel_template, tx_expiration_ts_median)) - change_contract_state(contract.second, tools::wallet_public::escrow_contract_details_basic::contract_accepted, contract.first, "cancel acceptance expiration"); - break; + case tools::wallet_public::escrow_contract_details_basic::contract_cancel_proposal_sent: + if (is_tx_expired(contract.second.cancel_body.tx_cancel_template, tx_expiration_ts_median)) + change_contract_state(contract.second, tools::wallet_public::escrow_contract_details_basic::contract_accepted, contract.first, "cancel proposal expiration"); + break; + case tools::wallet_public::escrow_contract_details_basic::contract_released_cancelled: + if (contract.second.height == 0 && is_tx_expired(contract.second.cancel_body.tx_cancel_template, tx_expiration_ts_median)) + change_contract_state(contract.second, tools::wallet_public::escrow_contract_details_basic::contract_accepted, contract.first, "cancel acceptance expiration"); + break; } } } //---------------------------------------------------------------------------------------------------- -bool wallet2::refresh(size_t & blocks_fetched, bool& received_money, bool& ok, std::atomic& stop) +bool wallet2::refresh(size_t& blocks_fetched, bool& received_money, bool& ok, std::atomic& stop) { try { @@ -3003,20 +3038,20 @@ void wallet2::detach_blockchain(uint64_t including_height) // rollback incoming transfers from detaching subchain { - auto it = std::find_if(m_transfers.begin(), m_transfers.end(), [&](const transfer_details& td){return td.m_ptx_wallet_info->m_block_height >= including_height; }); - if (it != m_transfers.end()) + auto it_start = std::find_if(m_transfers.begin(), m_transfers.end(), [&](const transfer_container::value_type& tr_e){return tr_e.second.m_ptx_wallet_info->m_block_height >= including_height; }); + if (it_start != m_transfers.end()) { - size_t i_start = it - m_transfers.begin(); - for (size_t i = i_start; i != m_transfers.size(); i++) + for (auto it = it_start; it!= m_transfers.end(); it++) { + uint64_t i = it->first; //check for htlc - if (m_transfers[i].m_ptx_wallet_info->m_tx.vout[m_transfers[i].m_internal_output_index].type() == typeid(tx_out_bare) && - boost::get(m_transfers[i].m_ptx_wallet_info->m_tx.vout[m_transfers[i].m_internal_output_index]).target.type() == typeid(txout_htlc)) + if (it->second.m_ptx_wallet_info->m_tx.vout[it->second.m_internal_output_index].type() == typeid(tx_out_bare) && + boost::get(it->second.m_ptx_wallet_info->m_tx.vout[it->second.m_internal_output_index]).target.type() == typeid(txout_htlc)) { //need to find an entry in m_htlc and remove it - const txout_htlc& hltc = boost::get(boost::get(m_transfers[i].m_ptx_wallet_info->m_tx.vout[m_transfers[i].m_internal_output_index]).target); - uint64_t expiration_height = m_transfers[i].m_ptx_wallet_info->m_block_height + hltc.expiration; + const txout_htlc& hltc = boost::get(boost::get(it->second.m_ptx_wallet_info->m_tx.vout[it->second.m_internal_output_index]).target); + uint64_t expiration_height = it->second.m_ptx_wallet_info->m_block_height + hltc.expiration; auto pair_of_it = m_htlcs.equal_range(expiration_height); bool found = false; for (auto it = pair_of_it.first; it != pair_of_it.second; it++) @@ -3032,20 +3067,20 @@ void wallet2::detach_blockchain(uint64_t including_height) } - if (!(m_transfers[i].m_key_image == null_ki && is_watch_only())) + if (!(it->second.m_key_image == null_ki && is_watch_only())) { - auto it_ki = m_key_images.find(m_transfers[i].m_key_image); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it_ki != m_key_images.end(), "key image " << m_transfers[i].m_key_image << " not found"); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers[i].m_ptx_wallet_info->m_block_height >= including_height, "transfer #" << i << " block height is less than " << including_height); + auto it_ki = m_key_images.find(it->second.m_key_image); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it_ki != m_key_images.end(), "key image " << it->second.m_key_image << " not found"); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second.m_ptx_wallet_info->m_block_height >= including_height, "transfer #" << i << " block height is less than " << including_height); m_key_images.erase(it_ki); } remove_transfer_from_amount_gindex_map(i); ++transfers_detached; } - m_transfers.erase(it, m_transfers.end()); + m_transfers.erase(it_start, m_transfers.end()); } } - + for (uint64_t i = get_top_block_height(); i != including_height - 1 && i != 0; i--) { unprocess_htlc_triggers_on_block_removed(i); @@ -3055,9 +3090,10 @@ void wallet2::detach_blockchain(uint64_t including_height) //rollback spends // do not clear spent flag in spent transfers as corresponding txs are most likely in the pool // they will be moved into m_unconfirmed_txs for clearing in future (if tx will expire of removed from pool) - for (size_t i = 0, sz = m_transfers.size(); i < sz; ++i) + for (auto& tr_ : m_transfers) { - auto& tr = m_transfers[i]; + uint64_t i = tr_.first; + auto& tr = tr_.second; if (tr.m_spent_height >= including_height) { WLT_LOG_BLUE("Transfer [" << i << "] spent height: " << tr.m_spent_height << " -> 0, reason: detaching blockchain", LOG_LEVEL_1); @@ -3074,7 +3110,7 @@ void wallet2::detach_blockchain(uint64_t including_height) break; tr_hist_it = it; // note that tr_hist_it->height >= height } - + if (tr_hist_it != m_transfer_history.rend()) { auto it_from = --tr_hist_it.base(); @@ -3094,18 +3130,18 @@ void wallet2::detach_blockchain(uint64_t including_height) } m_transfer_history.erase(it_from, m_transfer_history.end()); } - + //rollback payments for (auto it = m_payments.begin(); it != m_payments.end(); ) { - if(including_height <= it->second.m_block_height) + if (including_height <= it->second.m_block_height) it = m_payments.erase(it); else ++it; } //detach in m_last_zc_global_indexs - while (m_last_zc_global_indexs.size() && including_height <= m_last_zc_global_indexs.begin()->first ) + while (m_last_zc_global_indexs.size() && including_height <= m_last_zc_global_indexs.begin()->first) { m_last_zc_global_indexs.erase(m_last_zc_global_indexs.begin()); } @@ -3300,7 +3336,7 @@ void wallet2::load_keys(const std::string& buff, const std::string& password, ui const currency::account_keys& keys = m_account.get_keys(); r = epee::serialization::load_t_from_binary(m_account, account_data); - r = r && verify_keys(keys.view_secret_key, keys.account_address.view_public_key); + r = r && verify_keys(keys.view_secret_key, keys.account_address.view_public_key); if (keys.spend_secret_key == currency::null_skey) m_watch_only = true; else @@ -3325,7 +3361,7 @@ void wallet2::assign_account(const currency::account_base& acc) void wallet2::generate(const std::wstring& path, const std::string& pass, bool auditable_wallet) { WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(validate_password(pass), "new wallet generation failed: password contains forbidden characters") - clear(); + clear(); prepare_file_names(path); m_password = pass; @@ -3347,7 +3383,7 @@ void wallet2::restore(const std::wstring& path, const std::string& pass, const s clear(); prepare_file_names(path); m_password = pass; - + if (tracking_wallet) { r = m_account.restore_from_tracking_seed(seed_or_tracking_seed); @@ -3439,8 +3475,8 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) WLT_LOG_L0("Unknown wallet body version(" << wbh.m_ver << "), resync initiated."); need_to_resync = true; } - - + + if (m_watch_only && !is_auditable()) load_keys2ki(true, need_to_resync); @@ -3448,13 +3484,13 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) boost::system::error_code ec = AUTO_VAL_INIT(ec); m_current_wallet_file_size = boost::filesystem::file_size(wallet_, ec); - WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) - << " with public address " << m_account.get_public_address_str() + WLT_LOG_L0("Loaded wallet file" << (m_watch_only ? " (WATCH ONLY) " : " ") << string_encoding::convert_to_ansii(m_wallet_file) + << " with public address " << m_account.get_public_address_str() << ", file_size: " << m_current_wallet_file_size << ", blockchain_size: " << m_chain.get_blockchain_current_size() ); WLT_LOG_L1("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text()); - + load_votes_config(); WLT_LOG_L1("(after loading: pending_key_images: " << m_pending_key_images.size() << ", pki file elements: " << m_pending_key_images_file_container.size() << ", tx_keys: " << m_tx_keys.size() << ")"); @@ -3463,7 +3499,7 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password) { reset_history(); WLT_LOG_L0("Unable to load history data from wallet file, wallet will be resynced!"); - } + } THROW_IF_TRUE_WALLET_EX(need_to_resync, error::wallet_load_notice_wallet_restored, epee::string_encoding::convert_to_ansii(m_wallet_file)); } @@ -3532,7 +3568,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor WLT_LOG_L1("[LOADING]Blockchain shortener state: " << ENDL << m_chain.get_internal_state_text()); // for the sake of safety perform a double-renaming: wallet file -> old tmp, new tmp -> wallet file, remove old tmp - + boost::filesystem::path tmp_old_file_path = boost::filesystem::path(path_to_save); tmp_old_file_path += L".oldtmp_" + std::to_wstring(ts); @@ -3541,7 +3577,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor boost::filesystem::rename(path_to_save, tmp_old_file_path); WLT_LOG_L1("Renamed: " << ascii_path_to_save << " -> " << tmp_old_file_path.string()); } - + boost::filesystem::rename(tmp_file_path, path_to_save); WLT_LOG_L1("Renamed: " << tmp_file_path.string() << " -> " << ascii_path_to_save); @@ -3550,10 +3586,10 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor WLT_LOG_L1("Removed temporary file: " << tmp_old_file_path.string()); } - bool path_to_save_exists = boost::filesystem::is_regular_file(path_to_save); - bool tmp_file_path_exists = boost::filesystem::is_regular_file(tmp_file_path); - bool tmp_old_file_path_exists = boost::filesystem::is_regular_file(tmp_old_file_path); - + bool path_to_save_exists = boost::filesystem::is_regular_file(path_to_save); + bool tmp_file_path_exists = boost::filesystem::is_regular_file(tmp_file_path); + bool tmp_old_file_path_exists = boost::filesystem::is_regular_file(tmp_old_file_path); + boost::system::error_code ec = AUTO_VAL_INIT(ec); m_current_wallet_file_size = boost::filesystem::file_size(path_to_save, ec); if (path_to_save_exists && !tmp_file_path_exists && !tmp_old_file_path_exists) @@ -3612,15 +3648,16 @@ void wallet2::store_watch_only(const std::wstring& path_to_save, const std::stri bool stub = false; wo.load_keys2ki(true, stub); // to create outkey2ki file } - + // populate pending key images for spent outputs (this will help to resync watch-only wallet) - for (size_t ti = 0; ti < wo.m_transfers.size(); ++ti) + for (const auto& tr : m_transfers) { - const auto& td = wo.m_transfers[ti]; + + const auto& td = tr.second; if (!td.is_spent()) continue; // only spent transfers really need to be stored, because watch-only wallet will not be able to figure out they were spent otherwise - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.m_internal_output_index < td.m_ptx_wallet_info->m_tx.vout.size(), "invalid transfer #" << ti); - if(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].type() != typeid(tx_out_bare)) + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.m_internal_output_index < td.m_ptx_wallet_info->m_tx.vout.size(), "invalid transfer #" << tr.first); + if (td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].type() != typeid(tx_out_bare)) continue; const currency::txout_target_v& out_t = boost::get(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]).target; if (out_t.type() != typeid(currency::txout_to_key)) @@ -3694,9 +3731,11 @@ bool wallet2::balance(std::unordered_map subtransfers_by_assets_map; - for(auto& utx : m_unconfirmed_txs) + for (auto& utx : m_unconfirmed_txs) { for (auto& subtransfer : utx.second.subtransfers) { @@ -3746,24 +3786,65 @@ bool wallet2::balance(std::unordered_mapsecond)) // if is_incoming == false, then we need to check for change and add it to total { - auto it_employed_entry = subtransfers_by_assets_map.find(emp_entry.asset_id); - if (it_employed_entry == subtransfers_by_assets_map.end() || !(it_employed_entry->second)) // if is_incoming == false, then we need to check for change and add it to total + //it_employed_entry == subtransfers_by_assets_map.end() is a case when amount sent exactly equal amount received (someone producing more outputs for example) + //still need to add to total as it is a change + wallet_public::asset_balance_entry_base& e = balances[emp_entry.asset_id]; + e.total += emp_entry.amount; + } + } + //} + + } + + return true; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::truncate_wallet() +{ + if (m_concise_mode) + { + std::list items_to_remove; + for (auto& tr : m_transfers) + { + if (tr.second.is_spent() && tr.second.m_spent_height != 0 && !(tr.second.m_flags & WALLET_TRANSFER_DETAIL_CONCISE_MODE_PRESERVE) ) + { + if (tr.second.m_spent_height + m_wallet_concise_mode_max_reorg_blocks < m_chain.get_top_block_height()) { - //it_employed_entry == subtransfers_by_assets_map.end() is a case when amount sent exactly equal amount received (someone producing more outputs for example) - //still need to add to total as it is a change - wallet_public::asset_balance_entry_base& e = balances[emp_entry.asset_id]; - e.total += emp_entry.amount; + items_to_remove.push_back(tr.first); } } - //} - + } + + return truncate_transfers_and_history(items_to_remove); + } + return true; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::truncate_transfers_and_history(const std::list& items_to_remove) +{ + //delete from m_transfers + for (auto item : items_to_remove) + { + auto it = m_transfers.find(item); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_transfers.end(), + "internal error: item to delet " << item << " not found"); + m_transfers.erase(it); + } + + //delete from recent_history + if (m_truncate_history_max_entries != 0 && m_transfer_history.size() > m_truncate_history_max_entries) + { + m_transfer_history.erase(m_transfer_history.begin(), m_transfer_history.end() - m_truncate_history_max_entries); } return true; @@ -3786,9 +3867,9 @@ bool wallet2::balance(std::list& balances, u } asset_descriptor_base native_asset_info = AUTO_VAL_INIT(native_asset_info); - native_asset_info.full_name = CURRENCY_NAME_SHORT_BASE; - native_asset_info.ticker = CURRENCY_NAME_ABR; - native_asset_info.decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT; + native_asset_info.full_name = CURRENCY_NAME_SHORT_BASE; + native_asset_info.ticker = CURRENCY_NAME_ABR; + native_asset_info.decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT; custom_assets_local[currency::native_coin_asset_id] = native_asset_info; for (const auto& item : balances_map) @@ -3798,28 +3879,28 @@ bool wallet2::balance(std::list& balances, u //check if it custom asset auto it_cust = custom_assets_local.find(item.first); - if(it_cust == custom_assets_local.end()) + if (it_cust == custom_assets_local.end()) { - if(!m_use_assets_whitelisting) + if (!m_use_assets_whitelisting) continue; auto it_local = m_whitelisted_assets.find(item.first); - if(it_local == m_whitelisted_assets.end()) + if (it_local == m_whitelisted_assets.end()) { WLT_LOG_YELLOW("WARNING: unknown asset " << item.first << " found and skipped; it's NOT included in balance", LOG_LEVEL_1); continue; } - else + else { asset_info = it_local->second; } } - else + else { asset_info = it_cust->second; custom_assets_local.erase(it_cust); } - + balances.push_back(wallet_public::asset_balance_entry()); wallet_public::asset_balance_entry& new_item = balances.back(); static_cast(new_item) = item.second; @@ -3938,7 +4019,7 @@ bool wallet2::delete_custom_asset_id(const crypto::public_key& asset_id) { m_custom_assets.erase(it); } - + return true; } //---------------------------------------------------------------------------------------------------- @@ -3956,10 +4037,10 @@ const std::unordered_map& w { return m_own_asset_descriptors; } - //---------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------- bool wallet2::load_whitelisted_tokens() const { - if(!m_use_assets_whitelisting) + if (!m_use_assets_whitelisting) return true; m_whitelisted_assets.clear(); @@ -4005,7 +4086,7 @@ bool wallet2::generate_utxo_defragmentation_transaction_if_needed(currency::tran transfer(ctp, ftp, false, nullptr); if (ftp.was_not_prepared) - return false; // no such UTXO were found, not an error + return false; // no such UTXO were found, not an error tx = ftp.tx; return true; @@ -4013,14 +4094,15 @@ bool wallet2::generate_utxo_defragmentation_transaction_if_needed(currency::tran //---------------------------------------------------------------------------------------------------- std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/, bool show_only_unknown /*= false*/, const std::string& filter_asset_ticker /*= std::string{}*/) const { - static const char* header = " index amount ticker g_index flags block tx out# asset id"; + static const char* header = " index amount ticker g_index flags block tx out# asset id"; std::stringstream ss; ss << header << ENDL; size_t count = 0; size_t unknown_assets_outs_count = 0; - for (size_t i = 0; i != m_transfers.size(); ++i) + for (const auto& tr : m_transfers) { - const transfer_details& td = m_transfers[i]; + uint64_t i = tr.first; + const transfer_details& td = tr.second; if ((td.is_spent() && !include_spent) || (!td.is_spent() && !include_unspent)) continue; @@ -4045,7 +4127,7 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu std::setw(6) << std::left << (native_coin ? std::string(" ") : adb.ticker) << " " << std::right << std::setw(7) << td.m_global_output_index << " " << std::setw(2) << std::setfill('0') << td.m_flags << std::setfill(' ') << ":" << - std::setw(7) << transfer_flags_to_str(td.m_flags) << " " << + std::setw(8) << transfer_flags_to_str(td.m_flags) << " " << std::setw(7) << td.m_ptx_wallet_info->m_block_height << " " << get_transaction_hash(td.m_ptx_wallet_info->m_tx) << " " << std::setw(4) << td.m_internal_output_index << " "; @@ -4053,7 +4135,7 @@ std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool inclu ss << " "; else ss << td.get_asset_id(); - + ss << ENDL; ++count; @@ -4083,7 +4165,7 @@ std::string wallet2::get_balance_str() const uint64_t mined = 0; balance(balances, mined); - auto native_coin_it = std::find_if(balances.begin(), balances.end(), [&](auto& v){ return v.asset_info.asset_id == currency::native_coin_asset_id; }); + auto native_coin_it = std::find_if(balances.begin(), balances.end(), [&](auto& v) { return v.asset_info.asset_id == currency::native_coin_asset_id; }); if (native_coin_it != balances.end()) { balances.push_front(*native_coin_it); @@ -4120,20 +4202,20 @@ std::string wallet2::get_balance_str_raw() const static const char* header = " balance unlocked / [balance total] ticker asset id DP flags"; std::stringstream ss; ss << header << ENDL; - + uint64_t dummy = 0; typedef std::unordered_map balances_map_t; balances_map_t balances_map; this->balance(balances_map, dummy); - auto print_map = [&](const balances_map_t& map){ - for(const auto& entry : map) + auto print_map = [&](const balances_map_t& map) { + for (const auto& entry : map) { uint32_t asset_flags = 0; asset_descriptor_base asset_info{}; bool has_info = get_asset_info(entry.first, asset_info, asset_flags); ss << " " << std::left << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, asset_info.decimal_point); - if(entry.second.total == entry.second.unlocked) + if (entry.second.total == entry.second.unlocked) ss << std::string(21 + 3, ' '); else ss << " / " << std::setw(21) << print_fixed_decimal_point_with_trailing_spaces(entry.second.total, asset_info.decimal_point); @@ -4162,7 +4244,7 @@ std::string wallet2::get_balance_str_raw() const } ss << ENDL; } - }; + }; auto balances_map_it = balances_map.find(native_coin_asset_id); if (balances_map_it != balances_map.end()) @@ -4178,23 +4260,23 @@ std::string wallet2::get_balance_str_raw() const //print whitelist ss << "WHITELIST: " << ENDL; - for(const auto& entry : m_whitelisted_assets) + for (const auto& entry : m_whitelisted_assets) { - ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL; + ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL; } // print custom list ss << "CUSTOM LIST: " << ENDL; - for(const auto& entry : m_custom_assets) + for (const auto& entry : m_custom_assets) { ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL; } // print own list ss << "OWN DESCRIPTORS LIST: " << ENDL; - - for(const auto& entry : m_own_asset_descriptors) + + for (const auto& entry : m_own_asset_descriptors) { ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL; } @@ -4206,12 +4288,12 @@ void wallet2::get_payments(const std::string& payment_id, std::listset_connectivity(timeout, WALLET_RCP_COUNT_ATTEMNTS); } //---------------------------------------------------------------------------------------------------- -void wallet2::export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions) +void wallet2::export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions) { //typedef int(*t_somefunc)(int, int); typedef void(*playout_cb_type)(std::ostream&, const wallet_public::wallet_transfer_info&, size_t); @@ -4601,7 +4683,7 @@ void wallet2::export_transaction_history(std::ostream& ss, const std::string& fo wti.fee = currency::get_tx_fee(wti.tx); cb(ss, wti, index); return true; - }); + }); if (format == "json") { @@ -4636,7 +4718,7 @@ bool wallet2::is_transfer_okay_for_pos(const transfer_details& tr, bool is_zarca //prevent staking of after-last-pow-coins if (get_blockchain_current_size() - tr.m_ptx_wallet_info->m_block_height <= m_core_runtime_config.min_coinstake_age) return false; - + if (tr.m_ptx_wallet_info->m_block_height > m_last_pow_block_h) return false; @@ -4663,12 +4745,12 @@ size_t wallet2::get_pos_entries_count() bool is_zarcanum_hf = is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM); size_t counter = 0; - for (size_t i = 0, size = m_transfers.size(); i < size; i++) + for (const auto& tr : m_transfers) { - auto& tr = m_transfers[i]; + auto& td = tr.second; uint64_t stake_unlock_time = 0; - if (!is_transfer_okay_for_pos(tr, is_zarcanum_hf, stake_unlock_time)) + if (!is_transfer_okay_for_pos(td, is_zarcanum_hf, stake_unlock_time)) continue; ++counter; @@ -4680,9 +4762,10 @@ size_t wallet2::get_pos_entries_count() bool wallet2::get_pos_entries(std::vector& entries) { bool is_zarcanum_hf = is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM); - for (size_t i = 0; i != m_transfers.size(); i++) + for (const auto& td : m_transfers) { - auto& tr = m_transfers[i]; + uint64_t i = td.first; + auto& tr = td.second; uint64_t stake_unlock_time = 0; if (!is_transfer_okay_for_pos(tr, is_zarcanum_hf, stake_unlock_time)) @@ -4714,8 +4797,8 @@ bool wallet2::proxy_to_daemon(const std::string& uri, const std::string& body, i bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t full_block_reward, const currency::pos_entry& pe, currency::tx_generation_context& miner_tx_tgc, currency::block& b) const { bool r = false; - WLT_CHECK_AND_ASSERT_MES(pe.wallet_index < m_transfers.size(), false, "invalid pe.wallet_index: " << pe.wallet_index); - const transfer_details& td = m_transfers[pe.wallet_index]; + //WLT_CHECK_AND_ASSERT_MES(pe.wallet_index < m_transfers.size(), false, "invalid pe.wallet_index: " << pe.wallet_index); + const transfer_details& td = m_transfers.at(pe.wallet_index); const transaction& source_tx = td.m_ptx_wallet_info->m_tx; const crypto::public_key source_tx_pub_key = get_tx_pub_key_from_extra(source_tx); WLT_CHECK_AND_ASSERT_MES(pe.tx_out_index < source_tx.vout.size(), false, "invalid pe.tx_out_index: " << pe.tx_out_index); @@ -4737,11 +4820,11 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful WLT_CHECK_AND_ASSERT_MES(stake_out_v.type() == typeid(tx_out_bare), false, "unexpected stake output type: " << stake_out_v.type().name() << ", expected: tx_out_bare"); const tx_out_bare& stake_out = boost::get(stake_out_v); WLT_CHECK_AND_ASSERT_MES(stake_out.target.type() == typeid(txout_to_key), false, "unexpected stake output target type: " << stake_out.target.type().name() << ", expected: txout_to_key"); - + NLSAG_sig& sig = boost::get(b.miner_tx.signatures[0]); txin_to_key& stake_input = boost::get(b.miner_tx.vin[1]); const txout_to_key& stake_out_target = boost::get(stake_out.target); - + // partially fill stake input stake_input.k_image = pe.keyimage; stake_input.amount = pe.amount; @@ -4764,7 +4847,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful THROW_IF_FALSE_WALLET_EX(decoys_resp.status != API_RETURN_CODE_BUSY, error::daemon_busy, "getrandom_outs1.bin"); THROW_IF_FALSE_WALLET_EX(decoys_resp.status == API_RETURN_CODE_OK, error::get_random_outs_error, decoys_resp.status); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(decoys_resp.outs.size() == 1, "got wrong number of decoys batches: " << decoys_resp.outs.size()); - + // we expect that less decoys can be returned than requested, we will use them all anyway WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(decoys_resp.outs[0].outs.size() <= m_required_decoys_count + 1, "for PoS stake tx got greater decoys to mix than requested: " << decoys_resp.outs[0].outs.size() << " < " << m_required_decoys_count + 1); @@ -4773,7 +4856,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful std::unordered_set used_gindices; size_t good_outs_count = 0; - for(auto it = ring_candidates.begin(); it != ring_candidates.end(); ) + for (auto it = ring_candidates.begin(); it != ring_candidates.end(); ) { if (used_gindices.count(it->global_amount_index) != 0) { @@ -4788,15 +4871,15 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful } ++it; } - + // won't assert that ring_candidates.size() == m_required_decoys_count + 1 here as we will use all the decoys anyway if (ring_candidates.size() < m_required_decoys_count + 1) LOG_PRINT_YELLOW("PoS: using " << ring_candidates.size() - 1 << " decoys for mining tx, while " << m_required_decoys_count << " are required", LOG_LEVEL_1); - ring_candidates.sort([](auto& l, auto& r){ return l.global_amount_index < r.global_amount_index; }); // sort them now (note absolute_sorted_output_offsets_to_relative_in_place() below) + ring_candidates.sort([](auto& l, auto& r) { return l.global_amount_index < r.global_amount_index; }); // sort them now (note absolute_sorted_output_offsets_to_relative_in_place() below) uint64_t i = 0; - for(auto& el : ring_candidates) + for (auto& el : ring_candidates) { uint64_t gindex = el.global_amount_index; if (gindex == td.m_global_output_index) @@ -4829,10 +4912,10 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful " block hash: " << block_hash << ENDL << " key image: " << stake_input.k_image << ENDL << " ring:" << ENDL; - for(auto el: ring) + for (auto el : ring) ss << " " << *el << ENDL; ss << " signature:" << ENDL; - for(auto el: sig.s) + for (auto el : sig.s) ss << " " << el << ENDL; WLT_LOG_L4(ss.str()); } @@ -4881,7 +4964,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful std::unordered_set used_gindices; size_t good_outs_count = 0; - for(auto it = decoys.begin(); it != decoys.end(); ) + for (auto it = decoys.begin(); it != decoys.end(); ) { if (used_gindices.count(it->global_amount_index) != 0) { @@ -4898,10 +4981,10 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful } WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(decoys.size() == required_decoys_count + 1, "for PoS stake got less good decoys than required: " << decoys.size() << " < " << required_decoys_count); - decoys.sort([](auto& l, auto& r){ return l.global_amount_index < r.global_amount_index; }); // sort them now (note absolute_sorted_output_offsets_to_relative_in_place() below) + decoys.sort([](auto& l, auto& r) { return l.global_amount_index < r.global_amount_index; }); // sort them now (note absolute_sorted_output_offsets_to_relative_in_place() below) uint64_t i = 0; - for(auto& el : decoys) + for (auto& el : decoys) { uint64_t gindex = el.global_amount_index; if (gindex == td.m_global_output_index) @@ -4921,7 +5004,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful } stake_input.k_image = pe.keyimage; - crypto::point_t stake_out_blinded_asset_id_pt = currency::native_coin_asset_id_pt + td.m_zc_info_ptr->asset_id_blinding_mask * crypto::c_point_X; + crypto::point_t stake_out_blinded_asset_id_pt = currency::native_coin_asset_id_pt + td.m_zc_info_ptr->asset_id_blinding_mask * crypto::c_point_X; #ifndef NDEBUG { crypto::point_t source_amount_commitment = crypto::c_scalar_1div8 * td.m_amount * stake_out_blinded_asset_id_pt + crypto::c_scalar_1div8 * td.m_zc_info_ptr->amount_blinding_mask * crypto::c_point_G; @@ -4929,7 +5012,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful WLT_CHECK_AND_ASSERT_MES(ring[secret_index].amount_commitment == stake_out.amount_commitment, false, "ring secret member doesn't match with the stake output"); WLT_CHECK_AND_ASSERT_MES(cxt.stake_amount == td.m_amount, false, "stake_amount missmatch"); } - #endif +#endif crypto::hash hash_for_zarcanum_sig = get_block_hash(b); @@ -4945,7 +5028,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful uint8_t err = 0; r = crypto::zarcanum_generate_proof(hash_for_zarcanum_sig, cxt.kernel_hash, ring, cxt.last_pow_block_id_hashed, cxt.sk.kimage, - secret_x, cxt.secret_q, secret_index, cxt.stake_amount, td.m_zc_info_ptr->asset_id_blinding_mask, cxt.stake_out_amount_blinding_mask, pseudo_out_amount_blinding_mask, + secret_x, cxt.secret_q, secret_index, cxt.stake_amount, td.m_zc_info_ptr->asset_id_blinding_mask, cxt.stake_out_amount_blinding_mask, pseudo_out_amount_blinding_mask, static_cast(sig), &err); WLT_CHECK_AND_ASSERT_MES(r, false, "zarcanum_generate_proof failed, err: " << (int)err); @@ -4956,7 +5039,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful crypto::hash miner_tx_id = get_transaction_hash(b.miner_tx); // proofs for miner_tx - + // asset surjection proof currency::zc_asset_surjection_proof asp{}; r = generate_asset_surjection_proof(miner_tx_id, false, miner_tx_tgc, asp); // has_non_zc_inputs == false because after the HF4 PoS mining is only allowed for ZC stakes inputs @@ -4965,7 +5048,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful // range proofs currency::zc_outs_range_proof range_proofs{}; - r = generate_zc_outs_range_proof(miner_tx_id, 0, miner_tx_tgc, b.miner_tx.vout, range_proofs); + r = generate_zc_outs_range_proof(miner_tx_id, miner_tx_tgc, b.miner_tx.vout, range_proofs); WLT_CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()"); b.miner_tx.proofs.emplace_back(std::move(range_proofs)); @@ -4994,10 +5077,10 @@ bool wallet2::fill_mining_context(mining_context& ctx) ctx = mining_context{}; ctx.init(wide_difficulty_type(pos_details_resp.pos_basic_difficulty), pos_details_resp.sm, is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)); - ctx.last_block_hash = pos_details_resp.last_block_hash; - ctx.is_pos_allowed = pos_details_resp.pos_mining_allowed; + ctx.last_block_hash = pos_details_resp.last_block_hash; + ctx.is_pos_allowed = pos_details_resp.pos_mining_allowed; ctx.is_pos_sequence_factor_good = pos_details_resp.pos_sequence_factor_is_good; - ctx.starter_timestamp = pos_details_resp.starter_timestamp; + ctx.starter_timestamp = pos_details_resp.starter_timestamp; ctx.status = API_RETURN_CODE_NOT_FOUND; return true; } @@ -5013,7 +5096,7 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address mining_context ctx = AUTO_VAL_INIT(ctx); WLT_LOG_L2("Starting PoS mining iteration"); fill_mining_context(ctx); - + if (!ctx.is_pos_allowed) { WLT_LOG_YELLOW("POS MINING NOT ALLOWED YET", LOG_LEVEL_0); @@ -5027,7 +5110,7 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address } std::atomic stop(false); - scan_pos(ctx, stop, [this](){ + scan_pos(ctx, stop, [this]() { size_t blocks_fetched; refresh(blocks_fetched); if (blocks_fetched) @@ -5036,8 +5119,8 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address return false; } return true; - }, m_core_runtime_config); - + }, m_core_runtime_config); + bool res = true; if (ctx.status == API_RETURN_CODE_OK) { @@ -5050,10 +5133,10 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address return res; } //------------------------------------------------------------------ -void wallet2::do_pos_mining_prepare_entry(mining_context& context, size_t transfer_index) +void wallet2::do_pos_mining_prepare_entry(mining_context& context, const transfer_details& td) { - CHECK_AND_ASSERT_MES_NO_RET(transfer_index < m_transfers.size(), "transfer_index is out of bounds: " << transfer_index); - const transfer_details& td = m_transfers[transfer_index]; + //CHECK_AND_ASSERT_MES_NO_RET(transfer_index < m_transfers.size(), "transfer_index is out of bounds: " << transfer_index); + //const transfer_details& td = m_transfers.at(transfer_index); crypto::scalar_t amount_blinding_mask{}; if (td.is_zc()) @@ -5063,7 +5146,7 @@ void wallet2::do_pos_mining_prepare_entry(mining_context& context, size_t transf amount_blinding_mask, m_account.get_keys().view_secret_key); } //------------------------------------------------------------------ -bool wallet2::do_pos_mining_iteration(mining_context& context, size_t transfer_index, uint64_t ts) +bool wallet2::do_pos_mining_iteration(mining_context& context, uint64_t ts) { return context.do_iteration(ts); } @@ -5114,8 +5197,8 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco //found a block, construct it, sign and push to daemon WLT_LOG_GREEN("Found kernel, constructing block", LOG_LEVEL_0); - WLT_CHECK_AND_ASSERT_MES(cxt.index < m_transfers.size(), false, "cxt.index = " << cxt.index << " is out of bounds"); - const transfer_details& td = m_transfers[cxt.index]; + //WLT_CHECK_AND_ASSERT_MES(cxt.index < m_transfers.size(), false, "cxt.index = " << cxt.index << " is out of bounds"); + const transfer_details& td = m_transfers.at(cxt.index); currency::COMMAND_RPC_GETBLOCKTEMPLATE::request tmpl_req = AUTO_VAL_INIT(tmpl_req); currency::COMMAND_RPC_GETBLOCKTEMPLATE::response tmpl_rsp = AUTO_VAL_INIT(tmpl_rsp); @@ -5125,23 +5208,23 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco tmpl_req.extra_text = get_extra_text_for_block(m_chain.get_top_block_height()); tmpl_req.pe = AUTO_VAL_INIT(tmpl_req.pe); - tmpl_req.pe.amount = td.amount(); - tmpl_req.pe.block_timestamp = td.m_ptx_wallet_info->m_block_timestamp; - tmpl_req.pe.g_index = td.m_global_output_index; - tmpl_req.pe.keyimage = td.m_key_image; - tmpl_req.pe.stake_unlock_time = cxt.stake_unlock_time; - tmpl_req.pe.tx_id = td.tx_hash(); - tmpl_req.pe.tx_out_index = td.m_internal_output_index; - tmpl_req.pe.wallet_index = cxt.index; + tmpl_req.pe.amount = td.amount(); + tmpl_req.pe.block_timestamp = td.m_ptx_wallet_info->m_block_timestamp; + tmpl_req.pe.g_index = td.m_global_output_index; + tmpl_req.pe.keyimage = td.m_key_image; + tmpl_req.pe.stake_unlock_time = cxt.stake_unlock_time; + tmpl_req.pe.tx_id = td.tx_hash(); + tmpl_req.pe.tx_out_index = td.m_internal_output_index; + tmpl_req.pe.wallet_index = cxt.index; // mark stake source as spent and make sure it will be restored in case of error const std::vector stake_transfer_idx_vec{ cxt.index }; mark_transfers_as_spent(stake_transfer_idx_vec, "stake source"); bool gracefull_leaving = false; - auto stake_transfer_spent_flag_restorer = epee::misc_utils::create_scope_leave_handler([&](){ + auto stake_transfer_spent_flag_restorer = epee::misc_utils::create_scope_leave_handler([&]() { if (!gracefull_leaving) clear_transfers_from_flag(stake_transfer_idx_vec, WALLET_TRANSFER_DETAIL_FLAG_SPENT, "stake source"); - }); + }); // generate UTXO Defragmentation Transaction - to reduce the UTXO set size transaction udtx{}; @@ -5183,15 +5266,16 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco subm_req.b = t_serializable_object_to_blob(b); if (tmpl_req.explicit_transaction.size()) subm_req.explicit_txs.push_back(hexemizer{ tmpl_req.explicit_transaction }); - + m_core_proxy->call_COMMAND_RPC_SUBMITBLOCK2(subm_req, subm_rsp); if (subm_rsp.status != API_RETURN_CODE_OK) { WLT_LOG_ERROR("Constructed block " << print16(block_hash) << " was rejected by the core, status: " << subm_rsp.status); return false; - } + } WLT_LOG_GREEN("PoS block " << print16(block_hash) << " generated and accepted, congrats!", LOG_LEVEL_0); - m_wcallback->on_pos_block_found(b); + if (auto wcb = m_wcallback.lock()) + wcb->on_pos_block_found(b); gracefull_leaving = true; // to prevent source transfer flags be cleared in scope leave handler return true; @@ -5228,13 +5312,13 @@ bool wallet2::is_transfer_unlocked(const transfer_details& td) const //---------------------------------------------------------------------------------------------------- bool wallet2::is_transfer_unlocked(const transfer_details& td, bool for_pos_mining, uint64_t& stake_lock_time) const { - if (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_BLOCKED) - return false; + if (td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_BLOCKED) + return false; if (td.m_ptx_wallet_info->m_block_height + WALLET_DEFAULT_TX_SPENDABLE_AGE > get_blockchain_current_size()) return false; - + uint64_t unlock_time = get_tx_unlock_time(td.m_ptx_wallet_info->m_tx, td.m_internal_output_index); if (for_pos_mining && m_core_runtime_config.is_hardfork_active_for_height(1, get_blockchain_current_size())) @@ -5345,7 +5429,7 @@ uint64_t wallet2::get_alias_cost(const std::string& alias) { throw std::runtime_error(std::string("Failed to get alias cost")); } - + return rsp.reward; } //---------------------------------------------------------------------------------------------------- @@ -5402,13 +5486,44 @@ void wallet2::request_alias_registration(currency::extra_alias_entry& ai, curren transfer(destinations, 0, 0, fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), res_tx, CURRENCY_TO_KEY_OUT_RELAXED, false); } //---------------------------------------------------------------------------------------------------- +void wallet2::fill_ado_version_based_onhardfork(currency::asset_descriptor_operation& asset_reg_info) +{ + if (!is_in_hardfork_zone(ZANO_HARDFORK_05)) + { + asset_reg_info.version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; + } + else + { + asset_reg_info.version = ASSET_DESCRIPTOR_OPERATION_LAST_VER; + } +} +//---------------------------------------------------------------------------------------------------- +void wallet2::fill_adb_version_based_onhardfork(currency::asset_descriptor_base& asset_base) +{ + if (!is_in_hardfork_zone(ZANO_HARDFORK_05)) + { + asset_base.version = ASSET_DESCRIPTOR_BASE_HF4_VER; + } + else + { + asset_base.version = ASSET_DESCRIPTOR_BASE_LAST_VER; + } +} +//---------------------------------------------------------------------------------------------------- void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector& destinations, currency::finalized_tx& ft, crypto::public_key& new_asset_id) { WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(asset_info.decimal_point <= 18, "too big decimal point: " << (int)asset_info.decimal_point); + WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(validate_asset_ticker_and_full_name(asset_info), "ticker or full_name are invalid (perhaps they contain invalid symbols)"); asset_descriptor_operation asset_reg_info{}; - asset_reg_info.descriptor = asset_info; + fill_ado_version_based_onhardfork(asset_reg_info); + asset_reg_info.opt_descriptor = asset_info; + fill_adb_version_based_onhardfork(*asset_reg_info.opt_descriptor); asset_reg_info.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; + if (is_in_hardfork_zone(ZANO_HARDFORK_05)) + { + asset_reg_info.opt_asset_id_salt = crypto::rand(); + } construct_tx_param ctp = get_default_construct_tx_param(); ctp.dsts = destinations; ctp.extra.push_back(asset_reg_info); @@ -5422,7 +5537,7 @@ void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info CHECK_AND_ASSERT_THROW_MES(r, "asset_descriptor_operation cannot be found in tx extra as expected"); 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; + m_custom_assets[new_asset_id] = *ado.opt_descriptor; } //---------------------------------------------------------------------------------------------------- void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id) @@ -5436,12 +5551,19 @@ void wallet2::emit_asset(const crypto::public_key& asset_id, const std::vectorsecond.thirdparty_custody || own_asset_entry_it->second.owner_eth_pub_key.has_value() ) { send_to_network = false; ctp.additional_transfer_flags_to_mark = WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION; - ctp.tx_meaning_for_logs = "asset eth emission"; + ctp.tx_meaning_for_logs = "asset thirdparty/eth emission"; + ctp.ado_sign_thirdparty = true; } this->transfer(ctp, ft, send_to_network, nullptr); @@ -5477,7 +5600,9 @@ void wallet2::update_asset(const crypto::public_key& asset_id, const currency::a CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon"); asset_descriptor_operation asset_update_info{}; - asset_update_info.descriptor = new_descriptor; + fill_ado_version_based_onhardfork(asset_update_info); + asset_update_info.opt_descriptor = new_descriptor; + fill_adb_version_based_onhardfork(*asset_update_info.opt_descriptor); asset_update_info.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE; asset_update_info.opt_asset_id = asset_id; construct_tx_param ctp = get_default_construct_tx_param(); @@ -5512,14 +5637,16 @@ void wallet2::transfer_asset_ownership(const crypto::public_key& asset_id, const CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon"); asset_descriptor_operation asset_update_info{}; - asset_update_info.descriptor = last_adb; + fill_ado_version_based_onhardfork(asset_update_info); + asset_update_info.opt_descriptor = last_adb; + fill_adb_version_based_onhardfork(*asset_update_info.opt_descriptor); asset_update_info.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE; asset_update_info.opt_asset_id = asset_id; if (new_owner_v.type() == typeid(crypto::public_key)) - asset_update_info.descriptor.owner = boost::get(new_owner_v); + asset_update_info.opt_descriptor->owner = boost::get(new_owner_v); else - asset_update_info.descriptor.owner_eth_pub_key = boost::get(new_owner_v); + asset_update_info.opt_descriptor->owner_eth_pub_key = boost::get(new_owner_v); construct_tx_param ctp = get_default_construct_tx_param(); ctp.extra.push_back(asset_update_info); @@ -5543,17 +5670,21 @@ void wallet2::transfer_asset_ownership(const crypto::public_key& asset_id, const result_tx = ft.tx; } //---------------------------------------------------------------------------------------------------- -void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft) +void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft, const std::vector& service_entries, const std::string& address_to_point/* = const std::string()*/, uint64_t native_amount_to_point/* = 0*/) { - currency::asset_descriptor_base last_adb{}; - bool r = this->daemon_get_asset_info(asset_id, last_adb); - CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon"); - asset_descriptor_operation asset_burn_info{}; - asset_burn_info.descriptor = last_adb; - - CHECK_AND_ASSERT_THROW_MES(last_adb.current_supply >= amount_to_burn, "amount_to_burn is incorrect: " << print_money_brief(amount_to_burn, last_adb.decimal_point) << ", current_supply: " << print_money_brief(last_adb.current_supply, last_adb.decimal_point)); + fill_ado_version_based_onhardfork(asset_burn_info); + if (!is_in_hardfork_zone(ZANO_HARDFORK_05)) + { + currency::asset_descriptor_base last_adb{}; + bool r = this->daemon_get_asset_info(asset_id, last_adb); + CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon"); + asset_burn_info.opt_descriptor = last_adb; + fill_adb_version_based_onhardfork(*asset_burn_info.opt_descriptor); + CHECK_AND_ASSERT_THROW_MES(last_adb.current_supply >= amount_to_burn, "amount_to_burn is incorrect: " << print_money_brief(amount_to_burn, last_adb.decimal_point) << ", current_supply: " << print_money_brief(last_adb.current_supply, last_adb.decimal_point)); + } + currency::tx_destination_entry dst_to_burn{}; dst_to_burn.amount = amount_to_burn; dst_to_burn.asset_id = asset_id; @@ -5565,14 +5696,30 @@ void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_ ctp.need_at_least_1_zc = true; ctp.dsts.push_back(dst_to_burn); ctp.tx_meaning_for_logs = "asset burn"; + if (service_entries.size()) + { + //put it to extra + ctp.extra.insert(ctp.extra.end(), service_entries.begin(), service_entries.end()); + } + if (address_to_point.size()) + { + currency::account_public_address addr = AUTO_VAL_INIT(addr); + bool r = currency::get_account_address_from_str(addr, address_to_point); + CHECK_AND_ASSERT_THROW_MES(r, "WRONG_ADDRESS"); + currency::tx_destination_entry dst_to_point = AUTO_VAL_INIT(dst_to_point); + dst_to_point.asset_id = native_coin_asset_id; + dst_to_point.amount = native_amount_to_point; + dst_to_point.addr.push_back(addr); + ctp.dsts.push_back(dst_to_point); + } this->transfer(ctp, ft, true, nullptr); } //---------------------------------------------------------------------------------------------------- -void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::transaction& result_tx) +void wallet2::burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::transaction& result_tx, const std::vector& service_entries, const std::string& address_to_point/* = const std::string()*/, uint64_t native_amount_to_point /*= 0*/) { finalized_tx ft{}; - burn_asset(asset_id, amount_to_burn, ft); + burn_asset(asset_id, amount_to_burn, ft, service_entries, address_to_point, native_amount_to_point); result_tx = ft.tx; } //---------------------------------------------------------------------------------------------------- @@ -5594,14 +5741,14 @@ void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::tr COMMAND_RPC_GET_ALIAS_DETAILS::response rsp = AUTO_VAL_INIT(rsp); bool r = m_core_proxy->call_COMMAND_RPC_GET_ALIAS_DETAILS(req, rsp); CHECK_AND_ASSERT_THROW_MES(r, "Failed to call_COMMAND_RPC_GET_ALIAS_DETAILS"); - + CHECK_AND_ASSERT_THROW_MES(rsp.status == API_RETURN_CODE_OK, "call_COMMAND_RPC_GET_ALIAS_DETAILS response: " << rsp.status); - + currency::account_public_address addr = AUTO_VAL_INIT(addr); currency::get_account_address_from_str(addr, rsp.alias_details.address); - CHECK_AND_ASSERT_THROW_MES(m_account.get_public_address().spend_public_key == addr.spend_public_key && + CHECK_AND_ASSERT_THROW_MES(m_account.get_public_address().spend_public_key == addr.spend_public_key && m_account.get_public_address().view_public_key == addr.view_public_key, "call_COMMAND_RPC_GET_ALIAS_DETAILS: ownership is not confirmed"); if (!validate_alias_name(ai.m_alias)) @@ -5616,7 +5763,7 @@ void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::tr << "signed(owner) pub key: " << m_account.get_keys().account_address.spend_public_key << ENDL << "transfered to address: " << get_account_address_as_str(ai.m_address) << ENDL << "sign_buff_hash: " << currency::get_sign_buff_hash_for_alias_update(ai) - ); + ); std::vector destinations; std::vector extra; @@ -5628,7 +5775,7 @@ void wallet2::request_alias_update(currency::extra_alias_entry& ai, currency::tr } //---------------------------------------------------------------------------------------------------- bool wallet2::check_available_sources(std::list& amounts) -{ +{ /* std::list > holds; amounts.sort(); @@ -5651,7 +5798,7 @@ bool wallet2::check_available_sources(std::list& amounts) clear_transfers_from_flag(h, WALLET_TRANSFER_DETAIL_FLAG_BLOCKED, "check_available_sources"); add_transfers_to_transfers_cache(h); } - + WLT_LOG_MAGENTA("[CHECK_AVAILABLE_SOURCES]: " << amounts << " res: " << res << ENDL <<" holds: " << holds, LOG_LEVEL_0); return res; @@ -5683,28 +5830,34 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose) const { if (verbose) { - std::string res_buff; - local_transfers_struct lt(const_cast(m_transfers)); - epee::serialization::store_t_to_json(lt, res_buff); - ss << res_buff; + + ss << "{ \"transfers\": [" << ENDL; + for (const auto& tr : m_transfers) + { + uint64_t i = tr.first; + const transfer_details& td = tr.second; + ss << "{ \"i\": " << i << "," << ENDL; + ss << "\"entry\": " << epee::serialization::store_t_to_json(td) << "}," << ENDL; + } } else { boost::io::ios_flags_saver ifs(ss); ss << "index amount spent_h g_index block block_ts flg tx out# key image" << ENDL; - for (size_t i = 0; i != m_transfers.size(); i++) + for (const auto& tr : m_transfers) { - const transfer_details& td = m_transfers[i]; + uint64_t i = tr.first; + const transfer_details& td = tr.second; ss << std::right << - std::setw(5) << i << " " << - std::setw(21) << print_money(td.amount()) << " " << - std::setw(7) << td.m_spent_height << " " << - std::setw(7) << td.m_global_output_index << " " << - std::setw(6) << td.m_ptx_wallet_info->m_block_height << " " << - std::setw(10) << td.m_ptx_wallet_info->m_block_timestamp << " " << - std::setw(4) << td.m_flags << " " << - get_transaction_hash(td.m_ptx_wallet_info->m_tx) << " " << - std::setw(4) << td.m_internal_output_index << " " << + std::setw(5) << i << " " << + std::setw(21) << print_money(td.amount()) << " " << + std::setw(7) << td.m_spent_height << " " << + std::setw(7) << td.m_global_output_index << " " << + std::setw(6) << td.m_ptx_wallet_info->m_block_height << " " << + std::setw(10) << td.m_ptx_wallet_info->m_block_timestamp << " " << + std::setw(4) << td.m_flags << " " << + get_transaction_hash(td.m_ptx_wallet_info->m_tx) << " " << + std::setw(4) << td.m_internal_output_index << " " << td.m_key_image << ENDL; } } @@ -5719,7 +5872,7 @@ std::string wallet2::dump_trunsfers(bool verbose) const //---------------------------------------------------------------------------------------------------- void wallet2::dump_key_images(std::stringstream& ss) { - for (auto& ki: m_key_images) + for (auto& ki : m_key_images) { ss << "[" << ki.first << "]: " << ki.second << ENDL; } @@ -5755,7 +5908,7 @@ void wallet2::build_escrow_release_templates(crypto::hash multisig_id, //generate normal escrow release construct_params.dsts[0].amount = ecrow_details.amount_a_pledge; construct_params.dsts[1].amount = ecrow_details.amount_b_pledge + ecrow_details.amount_to_pay; - + //in case of ecrow_details.amount_a_pledge == 0 then exclude a if (construct_params.dsts[0].amount == 0) construct_params.dsts.erase(construct_params.dsts.begin()); @@ -5846,7 +5999,7 @@ void wallet2::build_escrow_template(const bc_services::contract_private_details& uint64_t b_release_fee, const std::string& payment_id, currency::transaction& tx, - std::vector& selected_transfers, + std::vector& selected_transfers, crypto::secret_key& one_time_key) { construct_tx_param ctp = AUTO_VAL_INIT(ctp); @@ -5900,10 +6053,10 @@ void wallet2::add_transfers_to_expiration_list(const std::vector& sele { // check all elements in selected_transfers for being already mentioned in m_money_expirations std::vector selected_transfers_local; - for(auto transfer_index : selected_transfers) + for (auto transfer_index : selected_transfers) { bool found = false; - for(auto it = m_money_expirations.begin(); !found && it != m_money_expirations.end(); ++it) + for (auto it = m_money_expirations.begin(); !found && it != m_money_expirations.end(); ++it) { auto& st = it->selected_transfers; found = std::find(st.begin(), st.end(), transfer_index) != st.end(); @@ -5924,13 +6077,13 @@ void wallet2::add_transfers_to_expiration_list(const std::vector& sele std::stringstream ss; for (auto tr_ind : m_money_expirations.back().selected_transfers) { - THROW_IF_FALSE_WALLET_INT_ERR_EX(tr_ind < m_transfers.size(), "invalid transfer index"); - uint32_t flags_before = m_transfers[tr_ind].m_flags; - m_transfers[tr_ind].m_flags |= WALLET_TRANSFER_DETAIL_FLAG_BLOCKED; - m_transfers[tr_ind].m_flags |= WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION; - ss << " " << std::right << std::setw(4) << tr_ind << " " << std::setw(21) << print_money(m_transfers[tr_ind].amount()) << " " - << std::setw(2) << std::left << flags_before << " -> " << std::setw(2) << std::left << m_transfers[tr_ind].m_flags << " " - << get_transaction_hash(m_transfers[tr_ind].m_ptx_wallet_info->m_tx) << std::endl; + //THROW_IF_FALSE_WALLET_INT_ERR_EX(tr_ind < m_transfers.size(), "invalid transfer index"); + uint32_t flags_before = m_transfers.at(tr_ind).m_flags; + m_transfers.at(tr_ind).m_flags |= WALLET_TRANSFER_DETAIL_FLAG_BLOCKED; + m_transfers.at(tr_ind).m_flags |= WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION; + ss << " " << std::right << std::setw(4) << tr_ind << " " << std::setw(21) << print_money(m_transfers.at(tr_ind).amount()) << " " + << std::setw(2) << std::left << flags_before << " -> " << std::setw(2) << std::left << m_transfers.at(tr_ind).m_flags << " " + << get_transaction_hash(m_transfers.at(tr_ind).m_ptx_wallet_info->m_tx) << std::endl; } WLT_LOG_GREEN(m_money_expirations.back().selected_transfers.size() << " transfer(s) added to expiration list:" << ENDL << "index amount flags tx hash" << ENDL << @@ -5939,14 +6092,15 @@ void wallet2::add_transfers_to_expiration_list(const std::vector& sele //---------------------------------------------------------------------------------------------------- void wallet2::remove_transfer_from_expiration_list(uint64_t transfer_index) { - THROW_IF_FALSE_WALLET_INT_ERR_EX(transfer_index < m_transfers.size(), "invalid transfer index"); - for(auto it = m_money_expirations.begin(); it != m_money_expirations.end(); /* nothing */) + //THROW_IF_FALSE_WALLET_INT_ERR_EX(transfer_index < m_transfers.size(), "invalid transfer index"); + auto& tr_entry = m_transfers.at(transfer_index); + for (auto it = m_money_expirations.begin(); it != m_money_expirations.end(); /* nothing */) { auto& st = it->selected_transfers; auto jt = std::find(st.begin(), st.end(), transfer_index); if (jt != st.end()) { - WLT_LOG_GREEN("Transfer [" << transfer_index << "], amount: " << print_money(m_transfers[transfer_index].amount()) << ", tx: " << get_transaction_hash(m_transfers[transfer_index].m_ptx_wallet_info->m_tx) << + WLT_LOG_GREEN("Transfer [" << transfer_index << "], amount: " << print_money(tr_entry.amount()) << ", tx: " << get_transaction_hash(tr_entry.m_ptx_wallet_info->m_tx) << " was removed from the expiration list", LOG_LEVEL_0); st.erase(jt); if (st.empty()) @@ -5958,20 +6112,20 @@ void wallet2::remove_transfer_from_expiration_list(uint64_t transfer_index) ++it; } // clear proposal reservation flag and blocked flag - uint32_t flags_before = m_transfers[transfer_index].m_flags; - m_transfers[transfer_index].m_flags &= ~WALLET_TRANSFER_DETAIL_FLAG_BLOCKED; - m_transfers[transfer_index].m_flags &= ~WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION; - if (flags_before != m_transfers[transfer_index].m_flags) + uint32_t flags_before = tr_entry.m_flags; + tr_entry.m_flags &= ~WALLET_TRANSFER_DETAIL_FLAG_BLOCKED; + tr_entry.m_flags &= ~WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION; + if (flags_before != tr_entry.m_flags) { - WLT_LOG_BLUE("Transfer [" << transfer_index << "] was cleared from escrow proposal reservation, flags: " << flags_before << " -> " << m_transfers[transfer_index].m_flags << ", reason: intentional removing from expiration list", LOG_LEVEL_0); + WLT_LOG_BLUE("Transfer [" << transfer_index << "] was cleared from escrow proposal reservation, flags: " << flags_before << " -> " << tr_entry.m_flags << ", reason: intentional removing from expiration list", LOG_LEVEL_0); } - + // (don't change m_spent flag, because transfer status is unclear - the caller should take care of it) } //---------------------------------------------------------------------------------------------------- void wallet2::send_escrow_proposal(const wallet_public::create_proposal_param& wp, - currency::transaction &proposal_tx, - currency::transaction &escrow_template_tx) + currency::transaction& proposal_tx, + currency::transaction& escrow_template_tx) { return send_escrow_proposal(wp.details, wp.fake_outputs_count, wp.unlock_time, wp.expiration_period, wp.fee, wp.b_fee, wp.payment_id, proposal_tx, escrow_template_tx); } @@ -5983,8 +6137,8 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details& uint64_t fee, uint64_t b_release_fee, const std::string& payment_id, - currency::transaction &tx, - currency::transaction &template_tx) + currency::transaction& tx, + currency::transaction& template_tx) { if (!is_connected_to_net()) { @@ -6026,9 +6180,9 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details& ftp.tx_version = this->get_current_tx_version(); try { - prepare_transaction(ctp, ftp); - crypto::secret_key sk = AUTO_VAL_INIT(sk); - finalize_transaction(ftp, tx, sk, false); + prepare_transaction(ctp, ftp); + crypto::secret_key sk = AUTO_VAL_INIT(sk); + finalize_transaction(ftp, tx, sk, false); } catch (...) { @@ -6038,14 +6192,14 @@ 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.attachments, ftp.prepared_destinations, ftp.selected_transfers); print_tx_sent_message(tx, "from multisig", true, fee); } //---------------------------------------------------------------------------------------------------- -void wallet2::create_htlc_proposal(uint64_t amount, const currency::account_public_address& addr, uint64_t lock_blocks_count, currency::transaction &tx, const crypto::hash& htlc_hash, std::string &origin) +void wallet2::create_htlc_proposal(uint64_t amount, const currency::account_public_address& addr, uint64_t lock_blocks_count, currency::transaction& tx, const crypto::hash& htlc_hash, std::string& origin) { construct_tx_param ctp = get_default_construct_tx_param(); ctp.fee = TX_DEFAULT_FEE; @@ -6056,7 +6210,7 @@ void wallet2::create_htlc_proposal(uint64_t amount, const currency::account_publ htlc_option.expiration = lock_blocks_count; //about 12 hours htlc_option.htlc_hash = htlc_hash; - currency::create_and_add_tx_payer_to_container_from_address(ctp.extra, + currency::create_and_add_tx_payer_to_container_from_address(ctp.extra, get_account().get_keys().account_address, get_top_block_height(), get_core_runtime_config()); finalized_tx ft = AUTO_VAL_INIT(ft); @@ -6069,8 +6223,12 @@ void wallet2::get_list_of_active_htlc(std::list& { for (auto htlc_entry : m_active_htlcs_txid) { - const transfer_details& td = m_transfers[htlc_entry.second]; - if (only_redeem_txs && !(td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM)) + //auto it = m_transfers.find(htlc_entry.second); + //if (it == m_transfers.end()) + // continue; + //const transfer_details& td = it->second; + const transfer_details& td = m_transfers.at(htlc_entry.second); + if (only_redeem_txs && !(td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM)) { continue; } @@ -6088,12 +6246,12 @@ void wallet2::get_list_of_active_htlc(std::list& "[get_list_of_active_htlc]Internal error: unexpected type of out"); const txout_htlc& htlc = boost::get(out_b.target); entry.sha256_hash = htlc.htlc_hash; - + currency::tx_payer payer = AUTO_VAL_INIT(payer); if (currency::get_type_in_variant_container(td.varian_options, payer)) entry.counterparty_address = payer.acc_addr; - entry.is_redeem = td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? true : false; + entry.is_redeem = td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM ? true : false; htlcs.push_back(entry); } } @@ -6118,7 +6276,7 @@ void wallet2::redeem_htlc(const crypto::hash& htlc_tx_id, const std::string& ori WLT_THROW_IF_FALSE_WITH_CODE(it != m_active_htlcs_txid.end(), "htlc not found with tx_id = " << htlc_tx_id, API_RETURN_CODE_NOT_FOUND); - ctp.dsts.back().amount = m_transfers[it->second].amount() - ctp.fee; + ctp.dsts.back().amount = m_transfers.at(it->second).amount() - ctp.fee; this->transfer(ctp, result_tx, true, nullptr); } //---------------------------------------------------------------------------------------------------- @@ -6130,7 +6288,7 @@ bool wallet2::check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& o "htlc not found with tx_id = " << htlc_tx_id, API_RETURN_CODE_NOT_FOUND); transfer_details_extra_option_htlc_info htlc_options = AUTO_VAL_INIT(htlc_options); - if (!currency::get_type_in_variant_container(m_transfers[it->second].varian_options, htlc_options)) + if (!currency::get_type_in_variant_container(m_transfers.at(it->second).varian_options, htlc_options)) { return false; } @@ -6146,7 +6304,7 @@ bool wallet2::check_htlc_redeemed(const crypto::hash& htlc_tx_id, std::string& o bool wallet2::create_ionic_swap_proposal(const wallet_public::ionic_swap_proposal_info& proposal_details, const currency::account_public_address& destination_addr, wallet_public::ionic_swap_proposal& proposal) { std::vector selected_transfers_for_template; - + return build_ionic_swap_template(proposal_details, destination_addr, proposal, selected_transfers_for_template); //const uint32_t mask_to_mark_escrow_template_locked_transfers = WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION; @@ -6161,13 +6319,13 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal WLT_THROW_IF_FALSE_WITH_CODE(proposal_detais.fee_paid_by_a >= get_current_minimum_network_fee(), "Error at build_ionic_swap_template, ", API_RETURN_CODE_WALLET_FEE_TOO_LOW); construct_tx_param ctp = get_default_construct_tx_param(); - + //ctp.fake_outputs_count = proposal_detais.mixins; ctp.fee = proposal_detais.fee_paid_by_a; ctp.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE; ctp.mark_tx_as_complete = false; ctp.crypt_address = destination_addr; - + ctp.dsts.resize(proposal_detais.to_finalizer.size() + proposal_detais.to_initiator.size()); size_t i = 0; // Here is an proposed for exchange funds @@ -6188,7 +6346,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal ctp.dsts[i].flags |= tx_destination_entry_flags::tdef_explicit_amount_to_provide; ctp.dsts[i].addr.push_back(m_account.get_public_address()); ctp.dsts[i].asset_id = proposal_detais.to_initiator[j].asset_id; - for_expiration_list.push_back(payment_details_subtransfer{ ctp.dsts[i].asset_id, ctp.dsts[i].amount}); + for_expiration_list.push_back(payment_details_subtransfer{ ctp.dsts[i].asset_id, ctp.dsts[i].amount }); } currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); @@ -6199,8 +6357,8 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal selected_transfers = ftp.selected_transfers; currency::finalized_tx finalize_result = AUTO_VAL_INIT(finalize_result); finalize_transaction(ftp, finalize_result, false); - for(uint64_t i: selected_transfers) - m_transfers[i].m_flags &= ~WALLET_TRANSFER_DETAIL_FLAG_BLOCKED; + for (uint64_t i : selected_transfers) + m_transfers.at(i).m_flags &= ~WALLET_TRANSFER_DETAIL_FLAG_BLOCKED; //add_transfers_to_expiration_list(selected_transfers, for_expiration_list, this->get_core_runtime_config().get_core_time() + proposal_detais.expiration_time, currency::null_hash); @@ -6210,11 +6368,11 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal ispc.gen_context = finalize_result.ftp.gen_context; //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); + proposal.encrypted_context = crypto::chacha_crypt(static_cast(proposal_context_blob), finalize_result.derivation); return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_ionic_swap_proposal_info(const std::string&raw_proposal, wallet_public::ionic_swap_proposal_info& proposal_info) const +bool wallet2::get_ionic_swap_proposal_info(const std::string& raw_proposal, wallet_public::ionic_swap_proposal_info& proposal_info) const { wallet_public::ionic_swap_proposal proposal = AUTO_VAL_INIT(proposal); bool r = t_unserializable_object_from_blob(proposal, raw_proposal); @@ -6255,7 +6413,7 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo std::unordered_map ammounts_to_b; //amounts to Bob (the one who received proposal), should BE funded std::vector bob_outs; bob_outs.resize(proposal.tx_template.vout.size()); - + for (const auto& o : outs) { THROW_IF_FALSE_WALLET_INT_ERR_EX(ionic_context.gen_context.asset_ids.size() > o.index, "Tx gen context has mismatch with tx(asset_ids) "); @@ -6306,7 +6464,7 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo return false; } amounts_provided_by_a[in_asset_id] += amount; - + //if (proposal_info.mixins == 0 || proposal_info.mixins > mx) //{ // proposal_info.mixins = mx; @@ -6328,9 +6486,9 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo { uint64_t amount_sent_back_to_initiator = ammounts_to_a[a.first]; - if (amounts_provided_by_a[a.first] < (a.second + amount_sent_back_to_initiator) ) + if (amounts_provided_by_a[a.first] < (a.second + amount_sent_back_to_initiator)) { - WLT_LOG_RED("Amount[" << a.first << "] provided by Alice(" << amounts_provided_by_a[a.first] << ") is less then transfered to Bob(" << a.second <<")", LOG_LEVEL_0); + WLT_LOG_RED("Amount[" << a.first << "] provided by Alice(" << amounts_provided_by_a[a.first] << ") is less then transfered to Bob(" << a.second << ")", LOG_LEVEL_0); return false; } amounts_provided_by_a[a.first] -= (amount_sent_back_to_initiator + a.second); @@ -6357,7 +6515,7 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo proposal_info.to_initiator.push_back(view::asset_funds{ a.first, a.second - amounts_provided_by_a[a.first] }); } - + return true; } @@ -6413,7 +6571,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.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; @@ -6423,7 +6581,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa //build transaction currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp); ftp.tx_version = this->get_current_tx_version(); - ftp.gen_context = ionic_context.gen_context; + ftp.gen_context = ionic_context.gen_context; prepare_transaction(construct_param, ftp, msc); @@ -6478,9 +6636,12 @@ bool wallet2::prepare_tx_sources_for_defragmentation_tx(std::vector= LOG_LEVEL_2) ss << "preparing sources for utxo defragmentation tx:"; - for (size_t i = 0, size = m_transfers.size(); i < size && selected_indicies.size() < m_max_utxo_count_for_defragmentation_tx; ++i) + for (const auto& tr : m_transfers)//size_t i = 0, size = m_transfers .size(); i < size && selected_indicies.size() < m_max_utxo_count_for_defragmentation_tx; ++i) { - const auto& td = m_transfers[i]; + if (selected_indicies.size() >= m_max_utxo_count_for_defragmentation_tx) + break; + uint64_t i = tr.first; + const auto& td = tr.second; if (!td.is_native_coin() || td.m_amount > m_max_allowed_output_amount_for_defragmentation_tx) continue; @@ -6514,7 +6675,7 @@ bool wallet2::prepare_tx_sources(assets_selection_context& needed_money_map, siz select_transfers(needed_money_map, fake_outputs_count, dust_threshold, selected_indicies); // always returns true, TODO consider refactoring -- sowle return prepare_tx_sources(fake_outputs_count, sources, selected_indicies); } - catch(...) + catch (...) { // if smth went wrong -- invalidate transfers cache to trigger its regeneration on the next use // it is necessary because it may be in invalid state (some items might be erased within select_indices_for_transfer() or expand_selection_with_zc_input()) @@ -6529,11 +6690,11 @@ void wallet2::prefetch_global_indicies_if_needed(const std::vector& se //std::list indices_that_requested_global_indicies; for (uint64_t i : selected_indicies) { - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers[i].m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, - "m_transfers[" << i << "].m_global_output_index is WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED"); - //indices_that_requested_global_indicies.push_back(i); - //txs.push_back(m_transfers[i].m_ptx_wallet_info->m_tx); - //} + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_transfers.at(i).m_global_output_index != WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED, + "m_transfers.at(" << i << ").m_global_output_index is WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED"); + //indices_that_requested_global_indicies.push_back(i); + //txs.push_back(m_transfers.at(i).m_ptx_wallet_info->m_tx); + //} } /* @@ -6544,7 +6705,7 @@ void wallet2::prefetch_global_indicies_if_needed(const std::vector& se auto it_ooutputs = outputs_for_all_txs.begin(); for (; it_ooutputs != outputs_for_all_txs.end();) { - transfer_details& td = m_transfers[*it_indices]; + transfer_details& td = m_transfers.at(*it_indices); td.m_global_output_index = (*it_ooutputs)[td.m_internal_output_index]; it_ooutputs++; it_indices++; }*/ @@ -6574,32 +6735,35 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys req.height_upper_limit = m_last_pow_block_h; // request decoys to be either older than, or the same age as stake output's height req.use_forced_mix_outs = false; // TODO: add this feature to UI later //req.decoys_count = fake_outputs_count + 1; // one more to be able to skip a decoy in case it hits the real output - for (uint64_t i: selected_indicies) + for (uint64_t i : selected_indicies) { req.amounts.push_back(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution()); COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::offsets_distribution& rdisttib = req.amounts.back(); - - auto it = m_transfers.begin() + i; - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->m_ptx_wallet_info->m_tx.vout.size() > it->m_internal_output_index, - "m_internal_output_index = " << it->m_internal_output_index << - " is greater or equal to outputs count = " << it->m_ptx_wallet_info->m_tx.vout.size()); - + + auto it = m_transfers.find(i); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_transfers.end(), + "internal error: index in m_tranfers " << i << " not found"); + + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second.m_ptx_wallet_info->m_tx.vout.size() > it->second.m_internal_output_index, + "m_internal_output_index = " << it->second.m_internal_output_index << + " is greater or equal to outputs count = " << it->second.m_ptx_wallet_info->m_tx.vout.size()); + //rdisttib.own_global_index = it->m_global_output_index; //check if we have Zarcanum era output of pre-Zarcanum - if (it->is_zc()) + if (it->second.is_zc()) { - if(this->is_auditable()) + if (this->is_auditable()) continue; //Zarcanum era rdisttib.amount = 0; //generate distribution in Zarcanum hardfork - build_distribution_for_input(rdisttib.global_offsets, it->m_global_output_index); + build_distribution_for_input(rdisttib.global_offsets, it->second.m_global_output_index); need_to_request = true; } else { //for prezarcanum era use flat distribution - rdisttib.amount = it->m_amount; + rdisttib.amount = it->second.m_amount; rdisttib.global_offsets.resize(fake_outputs_count + 1, 0); } } @@ -6637,7 +6801,7 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys if (!use_all_decoys_if_found_less_than_required) { // make sure we have received the requested number of decoys - for(size_t i = 0; i != daemon_resp.outs.size(); i++) + for (size_t i = 0; i != daemon_resp.outs.size(); i++) if (req.amounts[i].amount != 0 && daemon_resp.outs[i].outs.size() != req.amounts[i].global_offsets.size()) scanty_outs.push_back(daemon_resp.outs[i]); THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count); @@ -6653,19 +6817,21 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys size_t i = 0; for (uint64_t J : selected_indicies) { - auto it = m_transfers.begin() + J; + auto it = m_transfers.find(J); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it != m_transfers.end(), "internal error: J " << J << " not found in m_transfers"); + sources.push_back(AUTO_VAL_INIT(currency::tx_source_entry())); currency::tx_source_entry& src = sources.back(); - transfer_details& td = *it; - src.transfer_index = it - m_transfers.begin(); + transfer_details& td = it->second; + src.transfer_index = J; src.amount = td.amount(); src.asset_id = td.get_asset_id(); size_t fake_outputs_count = fake_outputs_count_; //redefine for hardfork if (td.is_zc() && !this->is_auditable()) fake_outputs_count = m_core_runtime_config.hf4_minimum_mixins; - + //paste mixin transaction if (daemon_resp.outs.size()) @@ -6679,18 +6845,18 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys { //TODO: make sure we have exact count needed } - - daemon_resp.outs[i].outs.sort([](const out_entry& a, const out_entry& b){return a.global_amount_index < b.global_amount_index; }); - for(out_entry& daemon_oe : daemon_resp.outs[i].outs) + + daemon_resp.outs[i].outs.sort([](const out_entry& a, const out_entry& b) {return a.global_amount_index < b.global_amount_index; }); + for (out_entry& daemon_oe : daemon_resp.outs[i].outs) { if (td.m_global_output_index == daemon_oe.global_amount_index) continue; tx_output_entry oe = AUTO_VAL_INIT(oe); - oe.amount_commitment = daemon_oe.amount_commitment; - oe.concealing_point = daemon_oe.concealing_point; - oe.out_reference = daemon_oe.global_amount_index; - oe.stealth_address = daemon_oe.stealth_address; - oe.blinded_asset_id = daemon_oe.blinded_asset_id; // TODO @#@# BAD DESIGN, consider refactoring -- sowle + oe.amount_commitment = daemon_oe.amount_commitment; + oe.concealing_point = daemon_oe.concealing_point; + oe.out_reference = daemon_oe.global_amount_index; + oe.stealth_address = daemon_oe.stealth_address; + oe.blinded_asset_id = daemon_oe.blinded_asset_id; // TODO @#@# BAD DESIGN, consider refactoring -- sowle src.outputs.push_back(oe); if (src.outputs.size() >= fake_outputs_count) break; @@ -6699,11 +6865,11 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys //paste real transaction to the random index auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) - { - if (a.out_reference.type().hash_code() == typeid(uint64_t).hash_code()) - return static_cast(boost::get(a.out_reference) >= td.m_global_output_index); - return false; // TODO: implement deterministics real output placement in case there're ref_by_id outs - }); + { + if (a.out_reference.type().hash_code() == typeid(uint64_t).hash_code()) + return static_cast(boost::get(a.out_reference) >= td.m_global_output_index); + return false; // TODO: implement deterministics real output placement in case there're ref_by_id outs + }); //size_t real_index = src.outputs.size() ? (rand() % src.outputs.size() ):0; tx_output_entry real_oe = AUTO_VAL_INIT(real_oe); real_oe.out_reference = td.m_global_output_index; // TODO: use ref_by_id when neccessary @@ -6724,17 +6890,17 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys VARIANT_SWITCH_END(); } VARIANT_CASE_CONST(tx_out_zarcanum, o); - real_oe.amount_commitment = o.amount_commitment; // TODO @#@# consider using shorter code like in sweep_below() (or better reuse it) - real_oe.concealing_point = o.concealing_point; - real_oe.stealth_address = o.stealth_address; - real_oe.blinded_asset_id = o.blinded_asset_id; - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.is_zc(), "transfer #" << J << ", amount: " << print_money_brief(td.amount()) << " is not a ZC"); - src.real_out_amount_blinding_mask = td.m_zc_info_ptr->amount_blinding_mask; - src.real_out_asset_id_blinding_mask = td.m_zc_info_ptr->asset_id_blinding_mask; - src.asset_id = td.m_zc_info_ptr->asset_id; + real_oe.amount_commitment = o.amount_commitment; // TODO @#@# consider using shorter code like in sweep_below() (or better reuse it) + real_oe.concealing_point = o.concealing_point; + real_oe.stealth_address = o.stealth_address; + real_oe.blinded_asset_id = o.blinded_asset_id; + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.is_zc(), "transfer #" << J << ", amount: " << print_money_brief(td.amount()) << " is not a ZC"); + src.real_out_amount_blinding_mask = td.m_zc_info_ptr->amount_blinding_mask; + src.real_out_asset_id_blinding_mask = td.m_zc_info_ptr->asset_id_blinding_mask; + src.asset_id = td.m_zc_info_ptr->asset_id; #ifndef NDEBUG - WLT_CHECK_AND_ASSERT_MES(crypto::point_t(src.asset_id) + src.real_out_asset_id_blinding_mask * crypto::c_point_X == crypto::point_t(real_oe.blinded_asset_id).modify_mul8(), false, "real_out_asset_id_blinding_mask doesn't match real_oe.blinded_asset_id"); - WLT_CHECK_AND_ASSERT_MES(td.m_amount * crypto::point_t(real_oe.blinded_asset_id).modify_mul8() + src.real_out_amount_blinding_mask * crypto::c_point_G == crypto::point_t(real_oe.amount_commitment).modify_mul8(), false, "real_out_amount_blinding_mask doesn't match real_oe.amount_commitment"); + WLT_CHECK_AND_ASSERT_MES(crypto::point_t(src.asset_id) + src.real_out_asset_id_blinding_mask * crypto::c_point_X == crypto::point_t(real_oe.blinded_asset_id).modify_mul8(), false, "real_out_asset_id_blinding_mask doesn't match real_oe.blinded_asset_id"); + WLT_CHECK_AND_ASSERT_MES(td.m_amount * crypto::point_t(real_oe.blinded_asset_id).modify_mul8() + src.real_out_amount_blinding_mask * crypto::c_point_G == crypto::point_t(real_oe.amount_commitment).modify_mul8(), false, "real_out_amount_blinding_mask doesn't match real_oe.amount_commitment"); #endif VARIANT_SWITCH_END(); @@ -6742,7 +6908,7 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx); src.real_output = interted_it - src.outputs.begin(); src.real_output_in_tx_index = td.m_internal_output_index; - + if (epee::log_space::get_set_log_detalisation_level() >= LOG_LEVEL_1) { std::stringstream ss; @@ -6750,7 +6916,7 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys print_source_entry(ss, src); WLT_LOG_L1(ss.str()); } - + ++i; } return true; @@ -6774,7 +6940,7 @@ void wallet2::select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS typedef currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; //TODO: This strategy would be a subject for continuous refactoring - + //first take all real transactions if ther are some std::list local_outs; std::list coinbases; @@ -6798,7 +6964,7 @@ void wallet2::select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS { coinbases.push_back(entry); continue; - } + } local_outs.push_back(entry); @@ -6812,7 +6978,7 @@ void wallet2::select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS } THROW_IF_FALSE_WALLET_INT_ERR_EX(local_outs.size() == m_core_runtime_config.hf4_minimum_mixins, "Amount is not 0 in zc decoys entry"); - amount_entry.outs = local_outs; + amount_entry.outs = local_outs; } //---------------------------------------------------------------------------------------------------------------- void wallet2::build_distribution_for_input(std::vector& offsets, uint64_t own_index) @@ -6863,10 +7029,10 @@ bool wallet2::prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string "htlc not found with tx_id = " << htlc_tx_id, API_RETURN_CODE_NOT_FOUND); } - WLT_THROW_IF_FALSE_WITH_CODE(m_transfers.size() > it->second, - "Internal error: index in m_active_htlcs_txid <" << it->second << "> is bigger then size of m_transfers <" << m_transfers.size() << ">", API_RETURN_CODE_INTERNAL_ERROR); + //WLT_THROW_IF_FALSE_WITH_CODE(m_transfers.size() > it->second, + // "Internal error: index in m_active_htlcs_txid <" << it->second << "> is bigger then size of m_transfers <" << m_transfers.size() << ">", API_RETURN_CODE_INTERNAL_ERROR); - const transfer_details& td = m_transfers[it->second]; + const transfer_details& td = m_transfers.at(it->second); //@#@ WLT_THROW_IF_FALSE_WITH_CODE(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].type() == typeid(tx_out_bare), "Unexpected out type in prepare_tx_sources_htlc:" << td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].type().name(), API_RETURN_CODE_INTERNAL_ERROR); @@ -6876,7 +7042,7 @@ bool wallet2::prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string "Unexpected type in active htlc", API_RETURN_CODE_INTERNAL_ERROR); const txout_htlc& htlc_out = boost::get(out_bare.target); - bool use_sha256 = !(htlc_out.flags&CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK); + bool use_sha256 = !(htlc_out.flags & CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK); //check origin WLT_THROW_IF_FALSE_WITH_CODE(origin.size() != 0, @@ -6913,16 +7079,16 @@ assets_selection_context wallet2::get_needed_money(uint64_t fee, const std::vect { assets_selection_context amounts_map; amounts_map[currency::native_coin_asset_id].needed_amount = fee; - for(auto& dt : dsts) + for (auto& dt : dsts) { - if(dt.asset_id == currency::null_pkey) + if (dt.asset_id == currency::null_pkey) continue; //this destination for emmition only THROW_IF_TRUE_WALLET_EX(0 == dt.amount, error::zero_destination); uint64_t money_to_add = dt.amount; if (dt.amount_to_provide || dt.flags & tx_destination_entry_flags::tdef_explicit_amount_to_provide) money_to_add = dt.amount_to_provide; - + amounts_map[dt.asset_id].needed_amount += money_to_add; THROW_IF_TRUE_WALLET_EX(amounts_map[dt.asset_id].needed_amount < money_to_add, error::tx_sum_overflow, dsts, fee); //clean up empty entries @@ -6941,7 +7107,8 @@ void wallet2::set_disable_tor_relay(bool disable) //---------------------------------------------------------------------------------------------------------------- void wallet2::notify_state_change(const std::string& state_code, const std::string& details) { - m_wcallback->on_tor_status_change(state_code); + if (auto wcb = m_wcallback.lock()) + wcb->on_tor_status_change(state_code); } //---------------------------------------------------------------------------------------------------------------- void wallet2::send_transaction_to_network(const transaction& tx) @@ -6951,7 +7118,7 @@ void wallet2::send_transaction_to_network(const transaction& tx) { //TODO check that core synchronized //epee::net_utils::levin_client2 p2p_client; - + //make few attempts tools::levin_over_tor_client p2p_client; p2p_client.get_transport().set_notifier(this); @@ -7022,8 +7189,8 @@ void wallet2::add_sent_tx_detailed_info(const transaction& tx, const std::vector } if (!recipients.size()) { - //transaction send to ourself - recipients.push_back(payment_id.empty() ? get_account_address_as_str(m_account.get_public_address()) : get_account_address_and_payment_id_as_str(m_account.get_public_address(), payment_id)); + //transaction send to ourself + recipients.push_back(payment_id.empty() ? get_account_address_as_str(m_account.get_public_address()) : get_account_address_and_payment_id_as_str(m_account.get_public_address(), payment_id)); } add_sent_unconfirmed_tx(tx, recipients, selected_transfers, destinations); @@ -7034,18 +7201,18 @@ void wallet2::mark_transfers_with_flag(const std::vector& selected_tra // check all selected transfers prior to flag change for (uint64_t i : selected_transfers) { - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(i < m_transfers.size(), "invalid transfer index given: " << i << ", m_transfers.size() == " << m_transfers.size()); + //WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(i < m_transfers.size(), "invalid transfer index given: " << i << ", m_transfers.size() == " << m_transfers.size()); if (throw_if_flag_already_set) { - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX((m_transfers[i].m_flags & flag) == 0, "transfer #" << i << " already has flag " << flag << ": " << m_transfers[i].m_flags << ", transfer info:" << ENDL << epee::serialization::store_t_to_json(m_transfers[i])); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX((m_transfers.at(i).m_flags & flag) == 0, "transfer #" << i << " already has flag " << flag << ": " << m_transfers.at(i).m_flags << ", transfer info:" << ENDL << epee::serialization::store_t_to_json(m_transfers.at(i))); } } for (uint64_t i : selected_transfers) { - uint32_t flags_before = m_transfers[i].m_flags; - m_transfers[i].m_flags |= flag; - WLT_LOG_L1("marking transfer #" << std::setfill('0') << std::right << std::setw(3) << i << " with flag " << flag << " : " << flags_before << " -> " << m_transfers[i].m_flags << + uint32_t flags_before = m_transfers.at(i).m_flags; + m_transfers.at(i).m_flags |= flag; + WLT_LOG_L1("marking transfer #" << std::setfill('0') << std::right << std::setw(3) << i << " with flag " << flag << " : " << flags_before << " -> " << m_transfers.at(i).m_flags << (reason.empty() ? "" : ", reason: ") << reason); } } @@ -7055,14 +7222,15 @@ void wallet2::clear_transfers_from_flag(const std::vector& selected_tr TRY_ENTRY(); for (uint64_t i : selected_transfers) { - if (i >= m_transfers.size()) - { - WLT_LOG_ERROR("INTERNAL ERROR: i: " << i << " >= m_transfers.size() : " << m_transfers.size()); - continue; - } - uint32_t flags_before = m_transfers[i].m_flags; - m_transfers[i].m_flags &= ~flag; - WLT_LOG_L1("clearing transfer #" << std::setfill('0') << std::right << std::setw(3) << i << " from flag " << flag << " : " << flags_before << " -> " << m_transfers[i].m_flags << + //if (i >= m_transfers.size()) + //{ + // WLT_LOG_ERROR("INTERNAL ERROR: i: " << i << " >= m_transfers.size() : " << m_transfers.size()); + // continue; + //} + auto& tr_entry = m_transfers.at(i); + uint32_t flags_before = tr_entry.m_flags; + tr_entry.m_flags &= ~flag; + WLT_LOG_L1("clearing transfer #" << std::setfill('0') << std::right << std::setw(3) << i << " from flag " << flag << " : " << flags_before << " -> " << tr_entry.m_flags << (reason.empty() ? "" : ", reason: ") << reason); } CATCH_ENTRY_NO_RETURN(); @@ -7091,79 +7259,79 @@ bool wallet2::extract_offers_from_transfer_entry(size_t i, std::unordered_map(ode) = od; - //fill extra fields - ode.tx_hash = m_transfer_history[i].tx_hash; - ode.index_in_tx = 0; // TODO: handle multiple offers in tx, now only one per tx is supported - ode.timestamp = m_transfer_history[i].timestamp; - ode.fee = m_transfer_history[i].fee; - ode.stopped = false; + WLT_LOG_ERROR("Transaction history entry " << i << " market as type " << m_transfer_history[i].tx_type << " but get_type_in_variant_container returned false for bc_services::offer_details"); break; } - case GUI_TX_TYPE_UPDATE_OFFER: + crypto::hash h = null_hash; + h = m_transfer_history[i].tx_hash; + bc_services::offer_details_ex& ode = offers_local[h]; + ode = AUTO_VAL_INIT(bc_services::offer_details_ex()); + static_cast(ode) = od; + //fill extra fields + ode.tx_hash = m_transfer_history[i].tx_hash; + ode.index_in_tx = 0; // TODO: handle multiple offers in tx, now only one per tx is supported + ode.timestamp = m_transfer_history[i].timestamp; + ode.fee = m_transfer_history[i].fee; + ode.stopped = false; + break; + } + case GUI_TX_TYPE_UPDATE_OFFER: + { + bc_services::update_offer uo; + if (!get_type_in_variant_container(m_transfer_history[i].marketplace_entries, uo)) { - bc_services::update_offer uo; - if (!get_type_in_variant_container(m_transfer_history[i].marketplace_entries, uo)) - { - WLT_LOG_ERROR("Transaction history entry " << i << " market as type " << m_transfer_history[i].tx_type << " but get_type_in_variant_container returned false for update_offer"); - break; - } - crypto::hash h = null_hash; - h = m_transfer_history[i].tx_hash; - bc_services::offer_details_ex& ode = offers_local[h]; - ode = AUTO_VAL_INIT(bc_services::offer_details_ex()); - static_cast(ode) = uo.of; - //fill extra fields - ode.tx_hash = m_transfer_history[i].tx_hash; - ode.index_in_tx = 0; - ode.fee = m_transfer_history[i].fee; - ode.stopped = false; - ode.tx_original_hash = uo.tx_id; - //remove old transaction - crypto::hash h_old = uo.tx_id; - auto it = offers_local.find(h_old); - if (it == offers_local.end()) - { - WLT_LOG_L3("Unable to find original tx record " << h_old << " in update offer " << h); - break; - } - //keep original timestamp - ode.timestamp = it->second.timestamp; - offers_local.erase(it); + WLT_LOG_ERROR("Transaction history entry " << i << " market as type " << m_transfer_history[i].tx_type << " but get_type_in_variant_container returned false for update_offer"); break; } - case GUI_TX_TYPE_CANCEL_OFFER: + crypto::hash h = null_hash; + h = m_transfer_history[i].tx_hash; + bc_services::offer_details_ex& ode = offers_local[h]; + ode = AUTO_VAL_INIT(bc_services::offer_details_ex()); + static_cast(ode) = uo.of; + //fill extra fields + ode.tx_hash = m_transfer_history[i].tx_hash; + ode.index_in_tx = 0; + ode.fee = m_transfer_history[i].fee; + ode.stopped = false; + ode.tx_original_hash = uo.tx_id; + //remove old transaction + crypto::hash h_old = uo.tx_id; + auto it = offers_local.find(h_old); + if (it == offers_local.end()) + { + WLT_LOG_L3("Unable to find original tx record " << h_old << " in update offer " << h); + break; + } + //keep original timestamp + ode.timestamp = it->second.timestamp; + offers_local.erase(it); + break; + } + case GUI_TX_TYPE_CANCEL_OFFER: + { + bc_services::cancel_offer co; + if (!get_type_in_variant_container(m_transfer_history[i].marketplace_entries, co)) + { + WLT_LOG_ERROR("Transaction history entry " << i << " market as type " << m_transfer_history[i].tx_type << " but get_type_in_variant_container returned false for cancel_offer"); + break; + } + crypto::hash h = co.tx_id; + auto it = offers_local.find(h); + if (it == offers_local.end()) { - bc_services::cancel_offer co; - if (!get_type_in_variant_container(m_transfer_history[i].marketplace_entries, co)) - { - WLT_LOG_ERROR("Transaction history entry " << i << " market as type " << m_transfer_history[i].tx_type << " but get_type_in_variant_container returned false for cancel_offer"); - break; - } - crypto::hash h = co.tx_id; - auto it = offers_local.find(h); - if (it == offers_local.end()) - { WLT_LOG_L3("Unable to find original tx record " << h << " in cancel offer " << h); break; - } - offers_local.erase(it); - } - default: - ; + offers_local.erase(it); + + } + default: + ; } return true; @@ -7217,12 +7385,12 @@ bool wallet2::expand_selection_with_zc_input(assets_selection_context& needed_mo { for (auto it_in_amount = it->second.begin(); it_in_amount != it->second.end(); it_in_amount++) { - if (!m_transfers[*it_in_amount].is_zc()) + if (!m_transfers.at(*it_in_amount).is_zc()) { continue; } - if (is_transfer_ready_to_go(m_transfers[*it->second.begin()], fake_outputs_count)) + if (is_transfer_ready_to_go(m_transfers.at(*it->second.begin()), fake_outputs_count)) { asset_needed_money_item.found_amount += it->first; selected_indexes.push_back(*it_in_amount); @@ -7243,7 +7411,7 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money { for (auto& item : needed_money_map) { - if(item.second.needed_amount == 0) + if (item.second.needed_amount == 0) continue; const crypto::public_key asset_id = item.first; @@ -7262,7 +7430,7 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money bool found_zc_input = false; for (auto i : selected_indexes) { - if (m_transfers[i].is_zc()) + if (m_transfers.at(i).is_zc()) { found_zc_input = true; break; @@ -7294,15 +7462,15 @@ uint64_t wallet2::select_indices_for_transfer(std::vector& selected_in WLT_CHECK_AND_ASSERT_MES(it->second.size(), 0, "internal error: empty found_free_amounts map"); } uint64_t fake_outputs_count = fake_outputs_count_; - if (!this->is_auditable() && m_transfers[*it->second.begin()].is_zc()) + if (!this->is_auditable() && m_transfers.at(*it->second.begin()).is_zc()) { fake_outputs_count = m_core_runtime_config.hf4_minimum_mixins; } - if (is_transfer_ready_to_go(m_transfers[*it->second.begin()], fake_outputs_count)) + if (is_transfer_ready_to_go(m_transfers.at(*it->second.begin()), fake_outputs_count)) { found_money += it->first; selected_indexes.push_back(*it->second.begin()); - WLT_LOG_L2("Selected index: " << *it->second.begin() << ", transfer_details: " << ENDL << epee::serialization::store_t_to_json(m_transfers[*it->second.begin()])); + WLT_LOG_L2("Selected index: " << *it->second.begin() << ", transfer_details: " << ENDL << epee::serialization::store_t_to_json(m_transfers.at(*it->second.begin()))); selected_amounts_str += (selected_amounts_str.empty() ? "" : "+") + print_money_brief(it->first, decimal_point); ++outputs_found; } @@ -7311,7 +7479,7 @@ uint64_t wallet2::select_indices_for_transfer(std::vector& selected_in found_free_amounts.erase(it); } - + WLT_LOG_GREEN("Found " << print_money_brief(found_money, decimal_point) << " as " << outputs_found << " out(s): " << selected_amounts_str << ", found_free_amounts.size()=" << found_free_amounts.size() << (asset_id == native_coin_asset_id ? std::string() : std::string(", asset_id: ") + crypto::pod_to_hex(asset_id)), LOG_LEVEL_0); return found_money; @@ -7331,7 +7499,7 @@ bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_o if (!td.is_spendable()) return false; - const tx_out_v &out_v = td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]; + const tx_out_v& out_v = td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]; uint8_t mix_attr = CURRENCY_TO_KEY_OUT_RELAXED; if (get_mix_attr_from_tx_out_v(out_v, mix_attr)) @@ -7342,11 +7510,11 @@ bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_o VARIANT_SWITCH_BEGIN(out_v); VARIANT_CASE_CONST(tx_out_bare, o); - if (o.target.type() == typeid(txout_htlc)) - { - if (fake_outputs_count != 0) - return false; - } + if (o.target.type() == typeid(txout_htlc)) + { + if (fake_outputs_count != 0) + return false; + } VARIANT_SWITCH_END(); return true; @@ -7359,9 +7527,10 @@ bool wallet2::prepare_free_transfers_cache(uint64_t fake_outputs_count) if (!m_found_free_amounts.size() || fake_outputs_count != m_fake_outputs_count) { m_found_free_amounts.clear(); - for (size_t i = 0; i < m_transfers.size(); ++i) + for (const auto& tr : m_transfers) { - const transfer_details& td = m_transfers[i]; + uint64_t i = tr.first; + const transfer_details& td = tr.second; uint64_t fake_outputs_count_local = fake_outputs_count; if (td.m_zc_info_ptr) { @@ -7386,7 +7555,7 @@ void wallet2::add_transfers_to_transfers_cache(const std::vector& inde { //@#@ for (auto i : indexs) - add_transfer_to_transfers_cache(m_transfers[i].amount(), i, m_transfers[i].get_asset_id()); + add_transfer_to_transfers_cache(m_transfers.at(i).amount(), i, m_transfers.at(i).get_asset_id()); } //---------------------------------------------------------------------------------------------------- void wallet2::add_transfer_to_transfers_cache(uint64_t amount, uint64_t index, const crypto::public_key& asset_id /* = currency::native_coin_asset_id */) @@ -7400,10 +7569,10 @@ bool wallet2::select_transfers(assets_selection_context& needed_money_map, size_ return select_indices_for_transfer(needed_money_map, fake_outputs_count, selected_indicies); } //---------------------------------------------------------------------------------------------------- -void wallet2::add_sent_unconfirmed_tx(const currency::transaction& tx, - const std::vector& recipients, - const std::vector& selected_indicies, - const std::vector& splitted_dsts) +void wallet2::add_sent_unconfirmed_tx(const currency::transaction& tx, + const std::vector& recipients, + const std::vector& selected_indicies, + const std::vector& splitted_dsts) { PROFILE_FUNC("wallet2::add_sent_unconfirmed_tx"); process_transaction_context ptc(tx); @@ -7412,7 +7581,7 @@ void wallet2::add_sent_unconfirmed_tx(const currency::transaction& tx, ptc.remote_aliases.push_back(get_alias_for_address(addr)); handle_unconfirmed_tx(ptc); - wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, currency::get_transaction_hash(tx)); + wallet_public::wallet_transfer_info& unconfirmed_wti = misc_utils::get_or_insert_value_initialized(m_unconfirmed_txs, currency::get_transaction_hash(tx)); //override some info that might be missing unconfirmed_wti.selected_indicies = selected_indicies; } @@ -7444,15 +7613,15 @@ std::vector wallet2::get_aliases_for_address(const std::string& add } //---------------------------------------------------------------------------------------------------- void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, - const std::vector& attachments, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, + const std::vector& attachments, currency::transaction& tx) { transfer(dsts, fake_outputs_count, unlock_time, fee, extra, attachments, get_current_split_strategy(), tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx); } //---------------------------------------------------------------------------------------------------- void wallet2::transfer(const std::vector& dsts, size_t fake_outputs_count, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, const std::vector& attachments) { currency::transaction tx; @@ -7480,7 +7649,7 @@ void wallet2::process_genesis_if_needed(const currency::block& genesis, const st crypto::hash genesis_hash = get_block_hash(genesis); if (get_blockchain_current_size() == 1 && m_chain.get_genesis() != genesis_hash) - WLT_LOG_L0("Changing genesis block for wallet " << m_account.get_public_address_str() << ":" << ENDL << " " << m_chain.get_genesis() << " -> " << genesis_hash); + WLT_LOG_L0("Changing genesis block for wallet " << m_account.get_public_address_str() << ":" << ENDL << " " << m_chain.get_genesis() << " -> " << genesis_hash); //m_blockchain.clear(); @@ -7527,16 +7696,16 @@ uint64_t wallet2::get_tx_expiration_median() const WLT_LOG_ERROR("COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN failed, status: " << res.status); return 0; } - + return res.expiration_median; } //---------------------------------------------------------------------------------------------------- void wallet2::print_source_entry(std::stringstream& output, const currency::tx_source_entry& src) const { std::stringstream ss; - for(auto& el : src.outputs) + for (auto& el : src.outputs) ss << el.out_reference << " "; - + output << "amount: " << print_money_brief(src.amount, get_asset_decimal_point(src.asset_id)) << (src.is_zc() ? "" : " (bare)"); if (src.asset_id != currency::native_coin_asset_id) @@ -7548,7 +7717,7 @@ void wallet2::print_source_entry(std::stringstream& output, const currency::tx_s } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const +bool wallet2::get_tx_key(const crypto::hash& txid, crypto::secret_key& tx_key) const { const std::unordered_map::const_iterator i = m_tx_keys.find(txid); if (i == m_tx_keys.end()) @@ -7569,16 +7738,16 @@ void wallet2::prepare_tx_destinations(const assets_selection_context& needed_mon uint8_t tx_flags, std::vector& final_destinations) { - - /* - let's account all processes assets, so if there are some destinations - that haven't been present in needed_money_map we can add it to final destinations - (could be in ionic swaps for example) + + /* + let's account all processes assets, so if there are some destinations + that haven't been present in needed_money_map we can add it to final destinations + (could be in ionic swaps for example) */ std::unordered_set processed_assets; - for (auto& el: needed_money_map) + for (auto& el : needed_money_map) { - prepare_tx_destinations(el.second.needed_amount, el.second.found_amount, destination_split_strategy_id, dust_policy, dsts, el.first, final_destinations); + prepare_tx_destinations(el.second.needed_amount, el.second.found_amount, destination_split_strategy_id, dust_policy, dsts, el.first, final_destinations); processed_assets.insert(el.first); } @@ -7607,7 +7776,7 @@ void wallet2::prepare_tx_destinations(const assets_selection_context& needed_mon if (final_destinations.empty()) { // if there's no destinations -- make CURRENCY_TX_MIN_ALLOWED_OUTS empty destinations - for(size_t i = 0; i < CURRENCY_TX_MIN_ALLOWED_OUTS; ++i) + for (size_t i = 0; i < CURRENCY_TX_MIN_ALLOWED_OUTS; ++i) final_destinations.emplace_back(0, m_account.get_public_address()); } else if (final_destinations.size() < CURRENCY_TX_MIN_ALLOWED_OUTS) @@ -7618,7 +7787,7 @@ void wallet2::prepare_tx_destinations(const assets_selection_context& needed_mon size_t items_to_be_added = CURRENCY_TX_MIN_ALLOWED_OUTS - final_destinations.size(); // TODO: consider allowing to set them somewhere size_t num_digits_to_keep = CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP; - decompose_amount_randomly(de.amount, [&](uint64_t amount){ de.amount = amount; final_destinations.push_back(de); }, items_to_be_added, num_digits_to_keep); + decompose_amount_randomly(de.amount, [&](uint64_t amount) { de.amount = amount; final_destinations.push_back(de); }, items_to_be_added, num_digits_to_keep); WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(final_destinations.size() == CURRENCY_TX_MIN_ALLOWED_OUTS, "can't get necessary number of outputs using decompose_amount_randomly(), got " << final_destinations.size() << " while mininum is " << CURRENCY_TX_MIN_ALLOWED_OUTS); } @@ -7638,7 +7807,7 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money, if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)) { - for(auto& dst : dsts) + for (auto& dst : dsts) { if (dst.asset_id == asset_id) final_destinations.emplace_back(dst); @@ -7688,7 +7857,7 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx // // TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id // - if (ctp.flags & TX_FLAG_SIGNATURE_MODE_SEPARATE && tx_for_mode_separate.vout.size() ) + if (ctp.flags & TX_FLAG_SIGNATURE_MODE_SEPARATE && tx_for_mode_separate.vout.size()) { WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(get_tx_flags(tx_for_mode_separate) & TX_FLAG_SIGNATURE_MODE_SEPARATE, "tx_param.flags differs from tx.flags"); if (ftp.tx_version > TRANSACTION_VERSION_PRE_HF4) @@ -7696,7 +7865,7 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx for (const auto& el : msc.proposal_info.to_initiator) needed_money_map[el.asset_id].needed_amount += el.amount; } - + if (msc.escrow) needed_money_map[currency::native_coin_asset_id].needed_amount += (currency::get_outs_money_amount(tx_for_mode_separate) - get_inputs_money_amount(tx_for_mode_separate)); } @@ -7712,7 +7881,7 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx if (!prepare_tx_sources_for_defragmentation_tx(ftp.sources, ftp.selected_transfers, needed_money_map[currency::native_coin_asset_id].found_amount)) return false; } - catch(const error::not_enough_outs_to_mix&) { return false; } // if there's not enough decoys, return false to indicate minor non-fatal error + catch (const error::not_enough_outs_to_mix&) { return false; } // if there's not enough decoys, return false to indicate minor non-fatal error } else if (ctp.htlc_tx_id != currency::null_hash) { @@ -7727,7 +7896,7 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx //fill amount ctp.dsts.begin()->amount = needed_money_map[currency::native_coin_asset_id].found_amount - ctp.fee; - + } else if (ctp.multisig_id != currency::null_hash) { @@ -7760,6 +7929,7 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx ftp.flags = ctp.flags; ftp.multisig_id = ctp.multisig_id; ftp.spend_pub_key = m_account.get_public_address().spend_public_key; + ftp.ado_sign_thirdparty = ctp.ado_sign_thirdparty; /* TODO WLT_LOG_GREEN("[prepare_transaction]: get_needed_money_time: " << get_needed_money_time << " ms" @@ -7847,7 +8017,7 @@ void wallet2::transfer(const std::vector& dsts, const std::vector& attachments, detail::split_strategy_id_t destination_split_strategy_id, const tx_dust_policy& dust_policy, - currency::transaction &tx, + currency::transaction& tx, uint8_t tx_outs_attr, bool shuffle, uint8_t flags, @@ -7949,7 +8119,7 @@ void wallet2::check_and_throw_if_self_directed_tx_with_payment_id_requested(cons } //---------------------------------------------------------------------------------------------------- void wallet2::transfer(construct_tx_param& ctp, - currency::transaction &tx, + currency::transaction& tx, bool send_to_network, std::string* p_unsigned_filename_or_tx_blob_str) { @@ -8039,9 +8209,10 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public std::unordered_map fake_outs_for_selected_transfers; // tr index -> fake outs count selected_transfers.reserve(m_transfers.size()); fake_outs_for_selected_transfers.reserve(m_transfers.size()); - for (size_t i = 0; i < m_transfers.size(); ++i) + for (const auto& tr : m_transfers) { - const transfer_details& td = m_transfers[i]; + uint64_t i = tr.first; + const transfer_details& td = tr.second; size_t fake_outs_count_for_td = is_auditable() ? 0 : (td.is_zc() ? m_core_runtime_config.hf4_minimum_mixins : fake_outs_count); uint64_t amount = td.amount(); if (amount < threshold_amount && td.is_native_coin() && @@ -8058,7 +8229,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!selected_transfers.empty(), "No spendable outputs meet the criterion"); // sort by amount descending in order to spend bigger outputs first - std::sort(selected_transfers.begin(), selected_transfers.end(), [this](uint64_t a, uint64_t b) { return m_transfers[b].amount() < m_transfers[a].amount(); }); + std::sort(selected_transfers.begin(), selected_transfers.end(), [this](uint64_t a, uint64_t b) { return m_transfers.at(b).amount() < m_transfers.at(a).amount(); }); // limit RPC request with reasonable number of sources if (selected_transfers.size() > CURRENCY_TX_MAX_ALLOWED_INPUTS) @@ -8067,7 +8238,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public prefetch_global_indicies_if_needed(selected_transfers); size_t max_fake_outs_count = 0; - for(auto tr_idx : selected_transfers) + for (auto tr_idx : selected_transfers) if (max_fake_outs_count < fake_outs_for_selected_transfers[tr_idx]) max_fake_outs_count = fake_outs_for_selected_transfers[tr_idx]; @@ -8085,10 +8256,10 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public req.use_forced_mix_outs = false; req.decoys_count = max_fake_outs_count + 1; for (uint64_t i : selected_transfers) - req.amounts.push_back(m_transfers[i].is_zc() ? 0 : m_transfers[i].m_amount); + req.amounts.push_back(m_transfers.at(i).is_zc() ? 0 : m_transfers.at(i).m_amount); r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rpc_get_random_outs_resp); - + THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs1.bin"); THROW_IF_FALSE_WALLET_EX(rpc_get_random_outs_resp.status != API_RETURN_CODE_BUSY, error::daemon_busy, "getrandom_outs1.bin"); THROW_IF_FALSE_WALLET_EX(rpc_get_random_outs_resp.status == API_RETURN_CODE_OK, error::get_random_outs_error, rpc_get_random_outs_resp.status); @@ -8111,9 +8282,9 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public set_payment_id_to_tx(ftp.attachments, payment_id, is_hf4); // put encrypted payer info into the extra ftp.crypt_address = destination_addr; - + currency::create_and_add_tx_payer_to_container_from_address(ftp.extra, m_account.get_public_address(), get_top_block_height(), m_core_runtime_config); - + ftp.flags = 0; // ftp.multisig_id -- not required // ftp.prepared_destinations -- will be filled by prepare_tx_destinations @@ -8123,118 +8294,118 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public ftp.spend_pub_key = m_account.get_public_address().spend_public_key; // needed for offline signing ftp.tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED; ftp.unlock_time = 0; - - enum try_construct_result_t {rc_ok = 0, rc_too_few_outputs = 1, rc_too_many_outputs = 2, rc_create_tx_failed = 3 }; + + enum try_construct_result_t { rc_ok = 0, rc_too_few_outputs = 1, rc_too_many_outputs = 2, rc_create_tx_failed = 3 }; auto get_result_t_str = [](try_construct_result_t t) -> const char* - { return t == rc_ok ? "rc_ok" : t == rc_too_few_outputs ? "rc_too_few_outputs" : t == rc_too_many_outputs ? "rc_too_many_outputs" : t == rc_create_tx_failed ? "rc_create_tx_failed" : "unknown"; }; + { return t == rc_ok ? "rc_ok" : t == rc_too_few_outputs ? "rc_too_few_outputs" : t == rc_too_many_outputs ? "rc_too_many_outputs" : t == rc_create_tx_failed ? "rc_create_tx_failed" : "unknown"; }; auto try_construct_tx = [this, &selected_transfers, &rpc_get_random_outs_resp, &fake_outs_for_selected_transfers, &fee, &destination_addr] - (size_t st_index_upper_boundary, currency::finalize_tx_param& ftp, uint64_t& amount_swept) -> try_construct_result_t - { - amount_swept = 0; - ftp.gen_context = tx_generation_context{}; - ftp.sources.clear(); - ftp.prepared_destinations.clear(); - - // prepare inputs - ftp.sources.resize(st_index_upper_boundary); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(st_index_upper_boundary <= selected_transfers.size(), "index_upper_boundary = " << st_index_upper_boundary << ", selected_transfers.size() = " << selected_transfers.size()); - for (size_t st_index = 0; st_index < st_index_upper_boundary; ++st_index) + (size_t st_index_upper_boundary, currency::finalize_tx_param& ftp, uint64_t& amount_swept) -> try_construct_result_t { - currency::tx_source_entry& src = ftp.sources[st_index]; - uint64_t tr_index = selected_transfers[st_index]; - transfer_details& td = m_transfers[tr_index]; - src.transfer_index = tr_index; - src.amount = td.amount(); - amount_swept += src.amount; - - // populate src.outputs with mix-ins - if (rpc_get_random_outs_resp.outs.size()) - { - rpc_get_random_outs_resp.outs[st_index].outs.sort([](const out_entry& a, const out_entry& b) { return a.global_amount_index < b.global_amount_index; }); - for (out_entry& daemon_oe : rpc_get_random_outs_resp.outs[st_index].outs) - { - if (td.m_global_output_index == daemon_oe.global_amount_index) - continue; - src.outputs.emplace_back(daemon_oe.global_amount_index, daemon_oe.stealth_address, daemon_oe.concealing_point, daemon_oe.amount_commitment, daemon_oe.blinded_asset_id); - if (src.outputs.size() >= fake_outs_for_selected_transfers[tr_index]) - break; - } - } + amount_swept = 0; + ftp.gen_context = tx_generation_context{}; + ftp.sources.clear(); + ftp.prepared_destinations.clear(); - // insert real output into src.outputs - // TODO: bad design, we need to get rid of code duplicates below -- sowle - auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) + // prepare inputs + ftp.sources.resize(st_index_upper_boundary); + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(st_index_upper_boundary <= selected_transfers.size(), "index_upper_boundary = " << st_index_upper_boundary << ", selected_transfers.size() = " << selected_transfers.size()); + for (size_t st_index = 0; st_index < st_index_upper_boundary; ++st_index) { - if (a.out_reference.type().hash_code() == typeid(uint64_t).hash_code()) - return static_cast(boost::get(a.out_reference) >= td.m_global_output_index); - return false; // TODO: implement deterministics real output placement in case there're ref_by_id outs - }); - tx_output_entry real_oe = AUTO_VAL_INIT(real_oe); - txout_ref_v out_reference = td.m_global_output_index; // TODO: use ref_by_id when neccessary - std::vector::iterator interted_it = src.outputs.end(); - VARIANT_SWITCH_BEGIN(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]); - VARIANT_CASE_CONST(tx_out_bare, o) - { - VARIANT_SWITCH_BEGIN(o.target); - VARIANT_CASE_CONST(txout_to_key, o) - interted_it = src.outputs.emplace(it_to_insert, out_reference, o.key); - VARIANT_CASE_CONST(txout_htlc, htlc) - interted_it = src.outputs.emplace(it_to_insert, out_reference, htlc.pkey_refund); - VARIANT_CASE_OTHER() + currency::tx_source_entry& src = ftp.sources[st_index]; + uint64_t tr_index = selected_transfers[st_index]; + transfer_details& td = m_transfers.at(tr_index); + src.transfer_index = tr_index; + src.amount = td.amount(); + amount_swept += src.amount; + + // populate src.outputs with mix-ins + if (rpc_get_random_outs_resp.outs.size()) { - WLT_THROW_IF_FALSE_WITH_CODE(false, - "Internal error: unexpected type of target: " << o.target.type().name(), - API_RETURN_CODE_INTERNAL_ERROR); + rpc_get_random_outs_resp.outs[st_index].outs.sort([](const out_entry& a, const out_entry& b) { return a.global_amount_index < b.global_amount_index; }); + for (out_entry& daemon_oe : rpc_get_random_outs_resp.outs[st_index].outs) + { + if (td.m_global_output_index == daemon_oe.global_amount_index) + continue; + src.outputs.emplace_back(daemon_oe.global_amount_index, daemon_oe.stealth_address, daemon_oe.concealing_point, daemon_oe.amount_commitment, daemon_oe.blinded_asset_id); + if (src.outputs.size() >= fake_outs_for_selected_transfers[tr_index]) + break; + } } - VARIANT_SWITCH_END(); - } - VARIANT_CASE_CONST(tx_out_zarcanum, o); + + // insert real output into src.outputs + // TODO: bad design, we need to get rid of code duplicates below -- sowle + auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) + { + if (a.out_reference.type().hash_code() == typeid(uint64_t).hash_code()) + return static_cast(boost::get(a.out_reference) >= td.m_global_output_index); + return false; // TODO: implement deterministics real output placement in case there're ref_by_id outs + }); + tx_output_entry real_oe = AUTO_VAL_INIT(real_oe); + txout_ref_v out_reference = td.m_global_output_index; // TODO: use ref_by_id when neccessary + std::vector::iterator interted_it = src.outputs.end(); + VARIANT_SWITCH_BEGIN(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]); + VARIANT_CASE_CONST(tx_out_bare, o) + { + VARIANT_SWITCH_BEGIN(o.target); + VARIANT_CASE_CONST(txout_to_key, o) + interted_it = src.outputs.emplace(it_to_insert, out_reference, o.key); + VARIANT_CASE_CONST(txout_htlc, htlc) + interted_it = src.outputs.emplace(it_to_insert, out_reference, htlc.pkey_refund); + VARIANT_CASE_OTHER() + { + WLT_THROW_IF_FALSE_WITH_CODE(false, + "Internal error: unexpected type of target: " << o.target.type().name(), + API_RETURN_CODE_INTERNAL_ERROR); + } + VARIANT_SWITCH_END(); + } + VARIANT_CASE_CONST(tx_out_zarcanum, o); interted_it = src.outputs.emplace(it_to_insert, out_reference, o.stealth_address, o.concealing_point, o.amount_commitment, o.blinded_asset_id); - WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.is_zc(), "transfer #" << tr_index << ", amount: " << print_money_brief(td.amount()) << " is not a ZC"); - src.real_out_amount_blinding_mask = td.m_zc_info_ptr->amount_blinding_mask; + WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(td.is_zc(), "transfer #" << tr_index << ", amount: " << print_money_brief(td.amount()) << " is not a ZC"); + src.real_out_amount_blinding_mask = td.m_zc_info_ptr->amount_blinding_mask; src.real_out_asset_id_blinding_mask = td.m_zc_info_ptr->asset_id_blinding_mask; - src.asset_id = td.m_zc_info_ptr->asset_id; - VARIANT_SWITCH_END(); - src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx); - src.real_output = interted_it - src.outputs.begin(); - src.real_output_in_tx_index = td.m_internal_output_index; - } + src.asset_id = td.m_zc_info_ptr->asset_id; + VARIANT_SWITCH_END(); + src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx); + src.real_output = interted_it - src.outputs.begin(); + src.real_output_in_tx_index = td.m_internal_output_index; + } - if (amount_swept <= fee) - return rc_too_few_outputs; + if (amount_swept <= fee) + return rc_too_few_outputs; - // try to construct a transaction + // try to construct a transaction - assets_selection_context needed_money_map; - needed_money_map[currency::native_coin_asset_id] = {}; - const std::vector dsts({ tx_destination_entry(amount_swept - fee, destination_addr) }); - prepare_tx_destinations(needed_money_map, get_current_split_strategy(), tools::tx_dust_policy(), dsts, ftp.flags, ftp.prepared_destinations); + assets_selection_context needed_money_map; + needed_money_map[currency::native_coin_asset_id] = {}; + const std::vector dsts({ tx_destination_entry(amount_swept - fee, destination_addr) }); + prepare_tx_destinations(needed_money_map, get_current_split_strategy(), tools::tx_dust_policy(), dsts, ftp.flags, ftp.prepared_destinations); - currency::transaction tx = AUTO_VAL_INIT(tx); - crypto::secret_key tx_key = AUTO_VAL_INIT(tx_key); - try - { - finalize_transaction(ftp, tx, tx_key, false, false); - } - catch (error::tx_too_big&) - { - return rc_too_many_outputs; - } - catch (...) - { - return rc_create_tx_failed; - } + currency::transaction tx = AUTO_VAL_INIT(tx); + crypto::secret_key tx_key = AUTO_VAL_INIT(tx_key); + try + { + finalize_transaction(ftp, tx, tx_key, false, false); + } + catch (error::tx_too_big&) + { + return rc_too_many_outputs; + } + catch (...) + { + return rc_create_tx_failed; + } - return rc_ok; - }; + return rc_ok; + }; size_t st_index_upper_boundary = std::min(selected_transfers.size(), estimated_max_inputs); try_construct_result_t res = try_construct_tx(st_index_upper_boundary, ftp, amount_swept); WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(res != rc_too_few_outputs, st_index_upper_boundary << " biggest unspent outputs have total amount of " << print_money_brief(amount_swept) << " which is less than required fee: " << print_money_brief(fee) << ", transaction cannot be constructed"); - + if (res == rc_too_many_outputs) { WLT_LOG_L1("sweep_below: first try of try_construct_tx(" << st_index_upper_boundary << ") returned " << get_result_t_str(res)); @@ -8272,7 +8443,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public uint64_t amount_min = UINT64_MAX, amount_max = 0, amount_sum = 0; for (auto& i : selected_transfers) { - uint64_t amount = m_transfers[i].amount(); + uint64_t amount = m_transfers.at(i).amount(); amount_min = std::min(amount_min, amount); amount_max = std::max(amount_max, amount); amount_sum += amount; @@ -8291,7 +8462,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public ftp.selected_transfers.push_back(ftp.sources[i].transfer_index); outs_swept = ftp.sources.size(); - + if (m_watch_only) { @@ -8317,7 +8488,7 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception on sweep_below, tx id (might be wrong): ") + epee::string_tools::pod_to_hex(get_transaction_hash(*p_tx))); throw; } - + } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c454480a..8fcced41 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -50,6 +50,8 @@ #define WALLET_DEFAULT_TX_SPENDABLE_AGE CURRENCY_HF4_MANDATORY_MIN_COINAGE #define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1 +#define WALLET_CONCISE_MODE_MAX_REORG_BLOCKS CURRENCY_BLOCKS_PER_DAY * 7 //week +#define WALLET_CONCISE_MODE_MOBILE_MAX_HISTORY_SIZE 500 const uint64_t WALLET_MINIMUM_HEIGHT_UNSET_CONST = std::numeric_limits::max(); @@ -134,9 +136,9 @@ namespace tools std::unordered_map m_key_images; std::vector m_transfer_history; std::unordered_map m_unconfirmed_in_transfers; - std::unordered_map m_unconfirmed_txs; + unconfirmed_txs_container m_unconfirmed_txs; std::unordered_set m_unconfirmed_multisig_transfers; - std::unordered_map m_tx_keys; + tx_secrete_keys_container m_tx_keys; std::unordered_map m_own_asset_descriptors; std::unordered_map m_custom_assets; //assets that manually added by user mutable std::unordered_map m_whitelisted_assets; //assets that whitelisted @@ -149,13 +151,14 @@ namespace tools uint64_t m_last_pow_block_h = 0; std::list> m_rollback_events; std::list > m_last_zc_global_indexs; // , biggest height comes in front + //variables that not being serialized std::atomic m_last_bc_timestamp = 0; uint64_t m_height_of_start_sync = 0; std::atomic m_last_sync_percent = 0; mutable uint64_t m_current_wallet_file_size = 0; - bool m_use_assets_whitelisting = true; + bool m_use_assets_whitelisting = true; mutable std::optional m_has_bare_unspent_outputs; // recalculated each time the balance() is called // variables that should be part of state data object but should not be stored during serialization @@ -201,7 +204,17 @@ namespace tools a & m_chain; a & m_minimum_height; a & m_amount_gindex_to_transfer_id; - a & m_transfers; + if (ver <= 167) + { + std::deque transfer_container_old; + a& transfer_container_old; + for (size_t i = 0; i != transfer_container_old.size(); i++){m_transfers[i] = transfer_container_old[i];} + } + else + { + a& m_transfers; + } + a & m_multisig_transfers; a & m_key_images; a & m_unconfirmed_txs; @@ -234,7 +247,12 @@ namespace tools { //workaround for m_last_zc_global_indexs holding invalid index for last item m_last_zc_global_indexs.pop_front(); - } + } + if (ver <= 167) + { + return; + } + } }; @@ -393,7 +411,7 @@ namespace tools //i_wallet2_callback* callback() const { return m_wcallback; } //void callback(i_wallet2_callback* callback) { m_callback = callback; } void callback(std::shared_ptr callback) { m_wcallback = callback; m_do_rise_transfer = (callback != nullptr); } - i_wallet2_callback* get_callback() { return m_wcallback.get(); } + std::shared_ptr get_callback() { return m_wcallback.lock(); } void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; } bool has_related_alias_entry_unconfirmed(const currency::transaction& tx); @@ -422,13 +440,13 @@ namespace tools void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector& destinations, currency::transaction& result_tx, crypto::public_key& new_asset_id); void emit_asset(const crypto::public_key& asset_id, std::vector& destinations, currency::transaction& result_tx); void update_asset(const crypto::public_key& asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx); - void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::transaction& result_tx); + void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::transaction& result_tx, const std::vector& service_entries = std::vector(), const std::string& address_to_point = std::string(), uint64_t native_amount_to_point = 0); void transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::transaction& result_tx); void deploy_new_asset(const currency::asset_descriptor_base& asset_info, const std::vector& destinations, currency::finalized_tx& ft, crypto::public_key& new_asset_id); void emit_asset(const crypto::public_key& asset_id, const std::vector& destinations, currency::finalized_tx& ft); void update_asset(const crypto::public_key& asset_id, const currency::asset_descriptor_base& new_descriptor, currency::finalized_tx& ft); - void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft); + void burn_asset(const crypto::public_key& asset_id, uint64_t amount_to_burn, currency::finalized_tx& ft, const std::vector& service_entries = std::vector(), const std::string& address_to_point = std::string(), uint64_t native_amount_to_point = 0); void transfer_asset_ownership(const crypto::public_key& asset_id, const currency::asset_owner_pub_key_v& new_owner_v, currency::finalized_tx& ft); bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb); @@ -565,10 +583,12 @@ namespace tools currency::transaction &escrow_template_tx); bool check_connection(); + bool truncate_transfers_and_history(const std::list& items_to_remove); + bool truncate_wallet(); // PoS mining - void do_pos_mining_prepare_entry(mining_context& cxt, size_t transfer_index); - bool do_pos_mining_iteration(mining_context& cxt, size_t transfer_index, uint64_t ts); + void do_pos_mining_prepare_entry(mining_context& cxt, const transfer_details& td); + bool do_pos_mining_iteration(mining_context& cxt, uint64_t ts); template //do refresh as external callback bool scan_pos(mining_context& cxt, std::atomic& stop, idle_condition_cb_t idle_condition_cb, const currency::core_runtime_config &runtime_config); bool fill_mining_context(mining_context& ctx); @@ -732,6 +752,9 @@ namespace tools bool accept_ionic_swap_proposal(const std::string& raw_proposal, currency::transaction& result_tx); bool accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposal& proposal, currency::transaction& result_tx); + void fill_ado_version_based_onhardfork(currency::asset_descriptor_operation& asset_reg_info); + void fill_adb_version_based_onhardfork(currency::asset_descriptor_base& asset_base); + // Signing and auth bool sign_buffer(const std::string& buff, crypto::signature& sig); bool validate_sign(const std::string& buff, const crypto::signature& sig, const crypto::public_key& pkey); @@ -740,6 +763,9 @@ namespace tools bool is_in_hardfork_zone(uint64_t hardfork_index) const; //performance inefficient call, suitable only for rare ocasions or super lazy developers bool proxy_to_daemon(const std::string& uri, const std::string& body, int& response_code, std::string& response_body); + void set_concise_mode(bool enabled) { m_concise_mode = enabled; } + void set_concise_mode_reorg_max_reorg_blocks(uint64_t max_blocks) { m_wallet_concise_mode_max_reorg_blocks = max_blocks; } + void set_concise_mode_truncate_history(uint64_t max_entries) { m_truncate_history_max_entries = max_entries; } construct_tx_param get_default_construct_tx_param(); @@ -774,7 +800,7 @@ private: bool on_idle(); void unserialize_block_complete_entry(const currency::COMMAND_RPC_GET_BLOCKS_FAST::response& serialized, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& unserialized); - void pull_blocks(size_t& blocks_added, std::atomic& stop); + void pull_blocks(size_t& blocks_added, std::atomic& stop, bool& full_reset_needed); bool prepare_free_transfers_cache(uint64_t fake_outputs_count); bool select_transfers(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust, std::vector& selected_indicies); void add_transfers_to_transfers_cache(const std::vector& indexs); @@ -795,7 +821,7 @@ private: void add_to_last_zc_global_indexs(uint64_t h, uint64_t last_zc_output_index); uint64_t get_actual_zc_global_index(); void handle_pulled_blocks(size_t& blocks_added, std::atomic& stop, - currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks); + currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks, bool& full_reset_needed); std::string get_alias_for_address(const std::string& addr); std::vector get_aliases_for_address(const std::string& addr); bool is_connected_to_net(); @@ -942,7 +968,7 @@ private: std::atomic m_stop; std::shared_ptr m_core_proxy; - std::shared_ptr m_wcallback; + std::weak_ptr m_wcallback; currency::core_runtime_config m_core_runtime_config; @@ -958,8 +984,16 @@ private: std::string m_votes_config_path; tools::wallet_public::wallet_vote_config m_votes_config; + std::atomic m_concise_mode = true; //in this mode the wallet don't keep spent entries in m_transfers as well as m_recent_transfers longer then 100 entries uint64_t m_last_known_daemon_height = 0; - + uint64_t m_wallet_concise_mode_max_reorg_blocks = WALLET_CONCISE_MODE_MAX_REORG_BLOCKS; + uint64_t m_full_resync_requested_at_h = 0; + uint64_t m_truncate_history_max_entries +#ifdef MOBILE_WALLET_BUILD + = WALLET_CONCISE_MODE_MOBILE_MAX_HISTORY_SIZE; +#else + = 0; +#endif //this needed to access wallets state in coretests, for creating abnormal blocks and tranmsactions friend class test_generator; }; // class wallet2 @@ -1071,7 +1105,13 @@ namespace tools if (tr_index != UINT64_MAX) { - transfer_details& td = m_transfers[tr_index]; + auto it_tr = m_transfers.find(tr_index); + if (it_tr == m_transfers.end()) + { + throw tools::error::wallet_error_resync_needed(); + } + transfer_details& td = it_tr->second; + ptc.total_balance_change[td.get_asset_id()] -= td.amount(); if (td.is_native_coin()) { @@ -1121,9 +1161,9 @@ namespace tools ts_middle -= ts_middle % POS_SCAN_STEP; uint64_t ts_window = std::min(ts_middle - ts_from, ts_to - ts_middle); - for (size_t transfer_index = 0; transfer_index != m_transfers.size(); transfer_index++) + for (auto it = m_transfers.begin(); it != m_transfers.end(); it++)//size_t transfer_index = 0; transfer_index != m_transfers.size(); transfer_index++) { - auto& tr = m_transfers[transfer_index]; + auto& tr = it->second; uint64_t stake_unlock_time = 0; if (!is_transfer_okay_for_pos(tr, cxt.zarcanum, stake_unlock_time)) @@ -1149,7 +1189,7 @@ namespace tools } }; - do_pos_mining_prepare_entry(cxt, transfer_index); + do_pos_mining_prepare_entry(cxt, tr); cxt.total_items_checked++; cxt.total_amount_checked += tr.amount(); while(step <= ts_window) @@ -1178,9 +1218,9 @@ namespace tools return false; cxt.iterations_processed++; - if (do_pos_mining_iteration(cxt, transfer_index, ts)) + if (do_pos_mining_iteration(cxt, ts)) { - cxt.index = transfer_index; + cxt.index = it->first; cxt.stake_unlock_time = stake_unlock_time; cxt.status = API_RETURN_CODE_OK; return true; diff --git a/src/wallet/wallet2_base.h b/src/wallet/wallet2_base.h index 3bf0e1ee..76fffc18 100644 --- a/src/wallet/wallet2_base.h +++ b/src/wallet/wallet2_base.h @@ -51,7 +51,8 @@ #define WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER uint32_t(1 << 3) #define WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION uint32_t(1 << 4) // transfer is reserved for cold-signing (unsigned tx was created and passed for signing) #define WALLET_TRANSFER_DETAIL_FLAG_HTLC_REDEEM uint32_t(1 << 5) // for htlc keeps info if this htlc belong as redeem or as refund -#define WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION uint32_t(1 << 6) // transfer is reserved for an ongoing asset operation with external signing +#define WALLET_TRANSFER_DETAIL_CONCISE_MODE_PRESERVE uint32_t(1 << 6) // do not truncate this output with CONCISE mode +#define WALLET_TRANSFER_DETAIL_FLAG_ASSET_OP_RESERVATION uint32_t(1 << 7) // transfer is reserved for an ongoing asset operation with external signing @@ -228,6 +229,9 @@ namespace tools // misc std::string tx_meaning_for_logs; // used to correctly log things, e.g. "escrow" or "asset emission". uint32_t additional_transfer_flags_to_mark = 0; + + //ado + bool ado_sign_thirdparty = false; }; struct mode_separate_context @@ -382,14 +386,16 @@ namespace tools return true; return false; } - static inline uint64_t transfer_details_base_to_amount(const transfer_details_base& tdb) + static inline bool transfer_details_base_to_amount(const transfer_details_base& tdb, uint64_t& val) { - return tdb.amount(); + val = tdb.amount(); + return true; } //---------------------------------------------------------------------------------------------------- - static inline std::string transfer_details_base_to_tx_hash(const transfer_details_base& tdb) + static inline bool transfer_details_base_to_tx_hash(const transfer_details_base& tdb, std::string& val) { - return epee::string_tools::pod_to_hex(currency::get_transaction_hash(tdb.m_ptx_wallet_info->m_tx)); + val = epee::string_tools::pod_to_hex(currency::get_transaction_hash(tdb.m_ptx_wallet_info->m_tx)); + return true; } @@ -511,12 +517,14 @@ namespace tools typedef std::unordered_multimap payment_container; - typedef std::deque transfer_container; + typedef std::map transfer_container; //typedef std::deque transfer_container; typedef std::unordered_map multisig_transfer_container; typedef std::unordered_map escrow_contracts_container; typedef std::map > free_amounts_cache_type; typedef std::unordered_map free_assets_amounts_cache_type; typedef std::unordered_map, uint64_t> amount_gindex_to_transfer_id_container; // maps [amount; gindex] -> tid + typedef std::unordered_map tx_secrete_keys_container; + typedef std::unordered_map unconfirmed_txs_container; }// namespace tools diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index f8b4e7fe..7479159b 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -321,6 +321,11 @@ namespace tools const currency::transaction m_tx; }; //---------------------------------------------------------------------------------------------------- + struct wallet_error_resync_needed : public std::exception + { + virtual const char* what() const noexcept override { return "wallet_error_resync_needed"; } + }; + //---------------------------------------------------------------------------------------------------- struct tx_parse_error : public refresh_error { explicit tx_parse_error(std::string&& loc, const currency::blobdata& tx_blob) diff --git a/src/wallet/wallet_id_adapter.h b/src/wallet/wallet_id_adapter.h index 73b3627b..f13ce0c7 100644 --- a/src/wallet/wallet_id_adapter.h +++ b/src/wallet/wallet_id_adapter.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Boolberry developers // Distributed under the MIT/X11 software license, see the accompanying @@ -29,31 +29,36 @@ struct i_wallet_to_i_backend_adapter: public tools::i_wallet2_callback m_wallet_id(wallet_id) {} - virtual void on_new_block(uint64_t height, const currency::block& block) { + virtual void on_new_block(uint64_t height, const currency::block& block) override + { m_pbackend->on_new_block(m_wallet_id, height, block); } - virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) { + virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, const std::list& balances, uint64_t total_mined) override + { m_pbackend->on_transfer2(m_wallet_id, wti, balances, total_mined); } - virtual void on_pos_block_found(const currency::block& wti) { + virtual void on_pos_block_found(const currency::block& wti) override + { m_pbackend->on_pos_block_found(m_wallet_id, wti); } - virtual void on_sync_progress(const uint64_t& progress) { + virtual void on_sync_progress(const uint64_t& progress) override + { m_pbackend->on_sync_progress(m_wallet_id, progress); } - virtual void on_transfer_canceled(const tools::wallet_public::wallet_transfer_info& wti) { + virtual void on_transfer_canceled(const tools::wallet_public::wallet_transfer_info& wti) override + { m_pbackend->on_transfer_canceled(m_wallet_id, wti); } - virtual void on_tor_status_change(const std::string& state) + virtual void on_tor_status_change(const std::string& state) override { m_pbackend->on_tor_status_change(m_wallet_id, state); } - virtual void on_mw_get_wallets(std::vector& wallets) + virtual void on_mw_get_wallets(std::vector& wallets) override { m_pbackend->on_mw_get_wallets(wallets); } - virtual bool on_mw_select_wallet(uint64_t wallet_id) + virtual bool on_mw_select_wallet(uint64_t wallet_id) override { return m_pbackend->on_mw_select_wallet(wallet_id); } diff --git a/src/wallet/wallet_public_structs_defs.h b/src/wallet/wallet_public_structs_defs.h index b6d78d46..74db48f9 100644 --- a/src/wallet/wallet_public_structs_defs.h +++ b/src/wallet/wallet_public_structs_defs.h @@ -153,7 +153,6 @@ namespace wallet_public std::vector service_entries; std::vector remote_addresses; //optional std::vector remote_aliases; //optional, describe only if there only one remote address - std::vector subtransfers; //not included in streaming serialization @@ -191,6 +190,8 @@ namespace wallet_public KV_SERIALIZE(remote_addresses) DOC_DSCR("Remote addresses of this transfer(destination if it's outgoing transfer or sender if it's incoming transaction)") DOC_EXMP_AUTO(1, "ZxBvJDuQjMG9R2j4WnYUhBYNrwZPwuyXrC7FHdVmWqaESgowDvgfWtiXeNGu8Px9B24pkmjsA39fzSSiEQG1ekB225ZnrMTBp") DOC_END KV_SERIALIZE(remote_aliases) DOC_DSCR("Aliases for remot addresses, of discovered") DOC_EXMP_AUTO(1, "roger") DOC_END KV_SERIALIZE(subtransfers) DOC_DSCR("Essential part of transfer entry: amounts that been transfered in this transaction grouped by asset id") DOC_EXMP_AUTO(1) DOC_END + + KV_SERIALIZE_EPHEMERAL_N(currency::asset_descriptor_operation, wallet_transfer_info_get_ado, "ado") DOC_DSCR("\"Asset Descriptor Operation\" if it was present in transaction") DOC_END END_KV_SERIALIZE_MAP() BEGIN_BOOST_SERIALIZATION() @@ -277,6 +278,13 @@ namespace wallet_public subtransfers.back().is_income = true; return subtransfers.back().amount; } + static inline bool wallet_transfer_info_get_ado(const wallet_transfer_info& tdb, currency::asset_descriptor_operation& val) + { + if (currency::get_type_in_variant_container(tdb.tx.extra, val)) + return true; + + return false; + } }; struct wallet_transfer_info_old : public wallet_transfer_info @@ -291,14 +299,16 @@ namespace wallet_public KV_CHAIN_BASE(wallet_transfer_info) END_KV_SERIALIZE_MAP() - static uint64_t wallet_transfer_info_to_amount(const wallet_transfer_info_old& wtio) + static bool wallet_transfer_info_to_amount(const wallet_transfer_info_old& wtio, uint64_t &val) { - return wtio.get_native_amount(); + val = wtio.get_native_amount(); + return true; } - static bool wallet_transfer_info_to_is_income(const wallet_transfer_info_old& wtio) + static bool wallet_transfer_info_to_is_income(const wallet_transfer_info_old& wtio, bool& val) { - return wtio.get_native_is_income(); + val = wtio.get_native_is_income(); + return true; } }; @@ -1002,92 +1012,6 @@ namespace wallet_public END_KV_SERIALIZE_MAP() }; - struct COMMAND_RPC_MAKETELEPOD - { - struct request - { - uint64_t amount; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(amount) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; //"OK", "INSUFFICIENT_COINS", "INTERNAL_ERROR" - telepod tpd; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - KV_SERIALIZE(tpd) - END_KV_SERIALIZE_MAP() - }; - }; - - - struct COMMAND_RPC_TELEPODSTATUS - { - struct request - { - telepod tpd; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(tpd) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; //"OK", "UNCONFIRMED", "BAD", "SPENT", "INTERNAL_ERROR" - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - END_KV_SERIALIZE_MAP() - }; - }; - - struct COMMAND_RPC_CLONETELEPOD - { - struct request - { - telepod tpd; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(tpd) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status;//"OK", "UNCONFIRMED", "BAD", "SPENT", "INTERNAL_ERROR:" - telepod tpd; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - KV_SERIALIZE(tpd) - END_KV_SERIALIZE_MAP() - }; - }; - - struct COMMAND_RPC_WITHDRAWTELEPOD - { - struct request - { - telepod tpd; - std::string addr; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(tpd) - KV_SERIALIZE(addr) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; //"OK", "UNCONFIRMED", "BAD", "SPENT", "INTERNAL_ERROR", "BAD_ADDRESS" - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - END_KV_SERIALIZE_MAP() - }; - }; - - struct create_proposal_param { // uint64_t wallet_id; @@ -2087,12 +2011,19 @@ namespace wallet_public struct request { - crypto::public_key asset_id; - uint64_t burn_amount; + crypto::public_key asset_id = currency::null_pkey; + uint64_t burn_amount = 0; + //optional params + std::string point_tx_to_address; + uint64_t native_amount = 0; + std::vector service_entries; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) DOC_DSCR("Id of the asset to burn") DOC_EXMP("40fa6db923728b38962718c61b4dc3af1acaa1967479c73703e260dc3609c58d") DOC_END KV_SERIALIZE(burn_amount) DOC_DSCR("Amount to burn") DOC_EXMP(10000000) DOC_END + KV_SERIALIZE(point_tx_to_address) DOC_DSCR("Optional, if we need this transaction to be seen by particular wallet") DOC_EXMP("ZxBvJDuQjMG9R2j4WnYUhBYNrwZPwuyXrC7FHdVmWqaESgowDvgfWtiXeNGu8Px9B24pkmjsA39fzSSiEQG1ekB225ZnrMTBp") DOC_END + KV_SERIALIZE(native_amount) DOC_DSCR("Optional, if we need this transaction to be seen by particular wallet") DOC_EXMP(0) DOC_END + KV_SERIALIZE(service_entries) DOC_DSCR("Optional, if we need to include service entries for burn transaction") DOC_EXMP_AUTO(1) DOC_END END_KV_SERIALIZE_MAP() }; @@ -2114,8 +2045,8 @@ namespace wallet_public { currency::blobdata finalized_tx; currency::blobdata unsigned_tx; - crypto::eth_signature eth_sig; - crypto::hash expected_tx_id; + crypto::eth_signature eth_sig; //TODO: add value initialization here + crypto::hash expected_tx_id = currency::null_hash; bool unlock_transfers_on_fail = false; BEGIN_KV_SERIALIZE_MAP() @@ -2130,7 +2061,7 @@ namespace wallet_public struct response { std::string status; - bool transfers_were_unlocked; + bool transfers_were_unlocked = false; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(status) DOC_DSCR("Status of the call") DOC_EXMP("OK") DOC_END diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 069e6856..4e30d514 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -212,7 +212,7 @@ namespace tools return epee::http_server_impl_base::init(m_port, m_bind_ip); } //------------------------------------------------------------------------------------------------------------------------------ - bool wallet_rpc_server::auth_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context) + bool wallet_rpc_server::auth_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& conn_context) { auto it = std::find_if(query_info.m_header_info.m_etc_fields.begin(), query_info.m_header_info.m_etc_fields.end(), [](const auto& element) @@ -252,7 +252,7 @@ namespace tools m_jwt_used_salts.add(salt, ticks_now + JWT_TOKEN_EXPIRATION_MAXIMUM); m_jwt_used_salts.remove_if_expiration_less_than(ticks_now); - LOG_PRINT_L0("JWT token OK"); + LOG_PRINT_L3("JWT token OK"); return true; } catch(const std::exception& e) @@ -266,12 +266,13 @@ namespace tools } //------------------------------------------------------------------------------------------------------------------------------ - bool wallet_rpc_server::handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context) + bool wallet_rpc_server::handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, epee::net_utils::connection_context_base& conn_context, bool& call_found, documentation& docs) { - if (m_jwt_secret.size() && m_conn_context.m_connection_id != RPC_INTERNAL_UI_CONTEXT) + if (m_jwt_secret.size() && conn_context.m_connection_id != RPC_INTERNAL_UI_CONTEXT) { - if (!auth_http_request(query_info, response, m_conn_context)) + if (!auth_http_request(query_info, response, conn_context)) { + call_found = true; response.m_response_code = 401; response.m_response_comment = "Unauthorized"; return true; @@ -281,14 +282,13 @@ namespace tools response.m_response_code = 200; response.m_response_comment = "Ok"; std::string reference_stub; - bool call_found = false; if (m_deaf) { response.m_response_code = 500; response.m_response_comment = "Internal Server Error"; return true; } - if (!handle_http_request_map(query_info, response, m_conn_context, call_found) && response.m_response_code == 200) + if (!handle_http_request_map(query_info, response, conn_context, call_found, docs) && response.m_response_code == 200) { response.m_response_code = 500; response.m_response_comment = "Internal Server Error"; @@ -1316,6 +1316,13 @@ namespace tools { WALLET_RPC_BEGIN_TRY_ENTRY(); + if (!currency::validate_asset_ticker_and_full_name(req.asset_descriptor)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT; + er.message = "asset ticker or full_name is invalid"; + return false; + } + std::vector currency_destinations; rpc_destinations_to_currency_destinations(req.destinations, true, !req.do_not_split_destinations, currency_destinations); @@ -1388,7 +1395,7 @@ namespace tools WALLET_RPC_BEGIN_TRY_ENTRY(); currency::finalized_tx ft{}; - w.get_wallet()->burn_asset(req.asset_id, req.burn_amount, ft); + w.get_wallet()->burn_asset(req.asset_id, req.burn_amount, ft, req.service_entries, req.point_tx_to_address, req.native_amount); res.tx_id = ft.tx_id; return true; @@ -1441,7 +1448,7 @@ namespace tools bool wallet_rpc_server::on_mw_get_wallets(const wallet_public::COMMAND_MW_GET_WALLETS::request& req, wallet_public::COMMAND_MW_GET_WALLETS::response& res, epee::json_rpc::error& er, connection_context& cntx) { WALLET_RPC_BEGIN_TRY_ENTRY(); - i_wallet2_callback* pcallback = w.get_wallet()->get_callback(); + std::shared_ptr pcallback = w.get_wallet()->get_callback(); if (!pcallback) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; @@ -1456,7 +1463,7 @@ namespace tools bool wallet_rpc_server::on_mw_select_wallet(const wallet_public::COMMAND_MW_SELECT_WALLET::request& req, wallet_public::COMMAND_MW_SELECT_WALLET::response& res, epee::json_rpc::error& er, connection_context& cntx) { WALLET_RPC_BEGIN_TRY_ENTRY(); - i_wallet2_callback* pcallback = w.get_wallet()->get_callback(); + std::shared_ptr pcallback = w.get_wallet()->get_callback(); if (!pcallback) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 70e3458b..a424e103 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -57,7 +57,9 @@ namespace tools { wallet_provider_simple(std::shared_ptr wallet_ptr) : m_wallet_ptr(wallet_ptr) {} - virtual std::shared_ptr get_wallet() + + // interface i_wallet_provider + virtual std::shared_ptr get_wallet() override { return m_wallet_ptr; } @@ -88,7 +90,18 @@ namespace tools static void init_options(boost::program_options::options_description& desc); bool init(const boost::program_options::variables_map& vm); bool run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address); - bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context); + + virtual bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info, + connection_context& conn_context) + { + bool call_found = false; + return this->handle_http_request(query_info, response_info, conn_context, call_found, epee::net_utils::http::i_chain_handler::m_empty_documentation); + } + + // interface i_chain_handler + virtual bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info, + epee::net_utils::connection_context_base& conn_context, bool& call_found, documentation& docs = epee::net_utils::http::i_chain_handler::m_empty_documentation) override; + void set_jwt_secret(const std::string& jwt); const std::string& get_jwt_secret(); diff --git a/src/wallet/wallets_manager.cpp b/src/wallet/wallets_manager.cpp index 3a08b448..8859ec8d 100644 --- a/src/wallet/wallets_manager.cpp +++ b/src/wallet/wallets_manager.cpp @@ -395,7 +395,13 @@ bool wallets_manager::start() CATCH_ENTRY_L0("main", false); } - +std::string wallets_manager::set_remote_node_url(const std::string& url) +{ + if (m_rpc_proxy) + m_rpc_proxy->set_connection_addr(url); + + return API_RETURN_CODE_OK; +} bool wallets_manager::stop() { @@ -1045,7 +1051,8 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st w->set_use_deffered_global_outputs(m_use_deffered_global_outputs); owr.wallet_id = m_wallet_id_counter++; - w->callback(std::shared_ptr(new i_wallet_to_i_backend_adapter(this, owr.wallet_id))); + std::shared_ptr w_cb{new i_wallet_to_i_backend_adapter(this, owr.wallet_id)}; + w->callback(w_cb); if (m_remote_node_mode) { w->set_core_proxy(m_rpc_proxy); @@ -1106,6 +1113,7 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st EXCLUSIVE_CRITICAL_REGION_LOCAL(m_wallets_lock); wallet_vs_options& wo = m_wallets[owr.wallet_id]; **wo.w = w; + wo.w_cb = w_cb; owr.wallet_file_size = w->get_wallet_file_size(); get_wallet_info(wo, owr.wi); init_wallet_entry(wo, owr.wallet_id); @@ -1921,7 +1929,10 @@ std::string wallets_manager::stop_pos_mining(uint64_t wallet_id) std::string wallets_manager::run_wallet(uint64_t wallet_id) { GET_WALLET_OPT_BY_ID(wallet_id, wo); - wo.miner_thread = std::thread(boost::bind(&wallets_manager::wallet_vs_options::worker_func, &wo)); + if (!wo.major_stop && !wo.miner_thread.joinable()) + { + wo.miner_thread = std::thread(boost::bind(&wallets_manager::wallet_vs_options::worker_func, &wo)); + } return API_RETURN_CODE_OK; } diff --git a/src/wallet/wallets_manager.h b/src/wallet/wallets_manager.h index 01c62062..4e7f73a0 100644 --- a/src/wallet/wallets_manager.h +++ b/src/wallet/wallets_manager.h @@ -55,6 +55,7 @@ public: { currency::core_runtime_config core_conf; epee::locked_object, wallet_lock_time_watching_policy> w; + std::shared_ptr w_cb; // not using locked_object here, cuz w_cb is accessed only via it's wallet -- sowle typedef epee::locked_object, wallet_lock_time_watching_policy>::lock_shared_ptr wallet_lock_object; std::shared_ptr rpc_wrapper; //500 bytes of extra data, we can afford it, to have rpc-like invoke map std::atomic do_mining; @@ -147,6 +148,7 @@ public: std::string get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res); std::string export_wallet_history(const view::export_wallet_info& ewi); std::string setup_wallet_rpc(const std::string& jwt_secret); + std::string set_remote_node_url(const std::string& url); #ifndef MOBILE_WALLET_BUILD currency::core_rpc_server& get_rpc_server() { return m_rpc_server; } @@ -206,10 +208,10 @@ private: virtual bool on_mw_select_wallet(uint64_t wallet_id) override; //----- i_wallet_provider ------ - virtual void lock(); - virtual void unlock(); + virtual void lock() override; + virtual void unlock() override; //#ifndef MOBILE_WALLET_BUILD - virtual std::shared_ptr get_wallet(); + virtual std::shared_ptr get_wallet() override; //#endif //-------- diff --git a/tests/core_tests/atomic_tests.cpp b/tests/core_tests/atomic_tests.cpp index f04d984a..bff1c87a 100644 --- a/tests/core_tests/atomic_tests.cpp +++ b/tests/core_tests/atomic_tests.cpp @@ -52,7 +52,7 @@ bool atomic_base_test::generate(std::vector& events) const test_core_time::adjust(m_genesis_timestamp); - epee::debug::get_set_enable_assert(true, true); + //epee::debug::get_set_enable_assert(true, true); currency::account_base genesis_acc; genesis_acc.generate(); @@ -68,7 +68,7 @@ bool atomic_base_test::generate(std::vector& events) const REWIND_BLOCKS_N(events, blk_0r, blk_0, m_mining_accunt, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5); DO_CALLBACK(events, "c1"); - epee::debug::get_set_enable_assert(true, false); + //epee::debug::get_set_enable_assert(true, false); return true; } @@ -78,8 +78,8 @@ bool atomic_base_test::generate(std::vector& events) const bool atomic_simple_test::c1(currency::core& c, size_t ev_index, const std::vector& events) { - epee::debug::get_set_enable_assert(true, true); - misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){epee::debug::get_set_enable_assert(true, false); }); + //epee::debug::get_set_enable_assert(true, true); + //misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){epee::debug::get_set_enable_assert(true, false); }); /* diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index d58568c3..2679dd39 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -997,6 +997,8 @@ bool test_generator::init_test_wallet(const currency::account_base& account, con w->set_genesis(genesis_hash); w->set_core_proxy(m_wallet_test_core_proxy); w->set_disable_tor_relay(true); + w->set_concise_mode(true); + w->set_concise_mode_reorg_max_reorg_blocks(TESTS_CONCISE_MODE_REORG_MAX_REORG_BLOCK); result = w; return true; @@ -1113,7 +1115,7 @@ bool test_generator::construct_pow_block_with_alias_info_in_coinbase(const accou miner_tx.proofs.emplace_back(std::move(currency::zc_asset_surjection_proof{})); // range proofs currency::zc_outs_range_proof range_proofs{}; - r = generate_zc_outs_range_proof(tx_id, 0, tx_gen_context, miner_tx.vout, range_proofs); + r = generate_zc_outs_range_proof(tx_id, tx_gen_context, miner_tx.vout, range_proofs); CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()"); miner_tx.proofs.emplace_back(std::move(range_proofs)); // balance proof @@ -2225,12 +2227,13 @@ bool make_tx_multisig_to_key(const currency::transaction& source_tx, bool estimate_wallet_balance_blocked_for_escrow(const tools::wallet2& w, uint64_t& result, bool substruct_change_from_result /* = true */) { - std::deque transfers; + tools::transfer_container transfers; w.get_transfers(transfers); result = 0; - for (const tools::transfer_details& td : transfers) + for (const auto& tr : transfers) { + const tools::transfer_details& td = tr.second; if (td.m_flags == (WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION)) result += td.amount(); } diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index c12a8fb6..1ff60a9a 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -19,8 +19,10 @@ #define TESTS_DEFAULT_FEE ((uint64_t)TX_DEFAULT_FEE) #define MK_TEST_COINS(amount) (static_cast(amount) * TX_DEFAULT_FEE) -#define TESTS_POS_CONFIG_MIN_COINSTAKE_AGE 4 -#define TESTS_POS_CONFIG_POS_MINIMUM_HEIGH 4 +#define TESTS_POS_CONFIG_MIN_COINSTAKE_AGE 4 +#define TESTS_POS_CONFIG_POS_MINIMUM_HEIGH 4 +#define TESTS_CONCISE_MODE_REORG_MAX_REORG_BLOCK 5 + namespace concolor { diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index 4810ed5f..703aec6f 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.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. @@ -17,25 +17,26 @@ template inline bool mine_next_pow_block_in_playtime(const currency::account_public_address& miner_addr, currency::core& c, t_callbacktype modify_block_cb, currency::block* output = nullptr) { - currency::block b = AUTO_VAL_INIT(b); - currency::wide_difficulty_type diff; - uint64_t height; - currency::blobdata extra = AUTO_VAL_INIT(extra); - bool r = c.get_block_template(b, miner_addr, miner_addr, diff, height, extra); + currency::create_block_template_params cbtp{}; + cbtp.ignore_pow_ts_check = true; + cbtp.miner_address = miner_addr; + currency::create_block_template_response cbtr{}; + bool r = c.get_block_template(cbtp, cbtr); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); + currency::block& b = cbtr.b; // adjust block's timestamp to keep difficulty low - currency::block last_block = AUTO_VAL_INIT(last_block); + currency::block last_block{}; c.get_blockchain_storage().get_top_block(last_block); b.timestamp = last_block.timestamp + DIFFICULTY_POW_TARGET; // keep global time up with blocks' timestamps test_core_time::adjust(b.timestamp); modify_block_cb(b); - r = currency::miner::find_nonce_for_given_block(b, diff, height); + r = currency::miner::find_nonce_for_given_block(b, cbtr.diffic, cbtr.height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); - currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); + currency::block_verification_context bvc{}; c.handle_incoming_block(t_serializable_object_to_blob(b), bvc); CHECK_AND_NO_ASSERT_MES(!bvc.m_verification_failed && !bvc.m_marked_as_orphaned && !bvc.m_already_exists, false, "block verification context check failed"); @@ -79,21 +80,23 @@ inline bool mine_next_pow_block_in_playtime_with_given_txs(const currency::accou static epee::critical_section s_locker; CHECK_AND_ASSERT_MES((height == SIZE_MAX) == (prev_id == currency::null_hash), false, "invalid agruments: height and prev_id should be specified or not specified together"); - currency::block b = AUTO_VAL_INIT(b); - currency::wide_difficulty_type diff; - uint64_t height_from_template = 0; - currency::blobdata extra = AUTO_VAL_INIT(extra); - currency::pos_entry pe = AUTO_VAL_INIT(pe); + currency::create_block_template_params cbtp{}; + cbtp.ignore_pow_ts_check = true; + cbtp.miner_address = miner_addr; + cbtp.pcustom_fill_block_template_func = loc_helper::fill_block_template_func; + currency::create_block_template_response cbtr{}; bool r = false; { CRITICAL_REGION_LOCAL(s_locker); loc_helper::txs_accessor() = &txs; - r = c.get_blockchain_storage().create_block_template(miner_addr, miner_addr, extra, false, pe, loc_helper::fill_block_template_func, b, diff, height_from_template); + r = c.get_block_template(cbtp, cbtr); + } CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); + currency::block& b = cbtr.b; // adjust block's timestamp to keep difficulty low - currency::block last_block = AUTO_VAL_INIT(last_block); + currency::block last_block{}; if (prev_id == currency::null_hash) r = c.get_blockchain_storage().get_top_block(last_block); else @@ -109,17 +112,17 @@ inline bool mine_next_pow_block_in_playtime_with_given_txs(const currency::accou CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() > 0, false, "invalid miner_tx.vin"); CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], currency::txin_gen, in, false); in.height = height; - set_tx_unlock_time(b.miner_tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + set_tx_unlock_time(b.miner_tx, cbtr.height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); } else { - height = height_from_template; + height = cbtr.height; } - r = currency::miner::find_nonce_for_given_block(b, diff, height); + r = currency::miner::find_nonce_for_given_block(b, cbtr.diffic, cbtr.height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); - currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); + currency::block_verification_context bvc{}; for (auto& tx : txs) { crypto::hash tx_id = currency::get_transaction_hash(tx); @@ -153,7 +156,7 @@ inline bool mine_next_pow_blocks_in_playtime_with_given_txs(const currency::acco std::vector txs_local = txs; crypto::hash prev_id_internal = prev_id; - currency::block prv_block = AUTO_VAL_INIT(prv_block); + currency::block prv_block{}; bool r = c.get_blockchain_storage().get_block_by_hash(prev_id, prv_block); CHECK_AND_ASSERT_MES(r, false, "block with id " << prev_id << " not found"); @@ -172,7 +175,7 @@ inline bool mine_next_pow_blocks_in_playtime_with_given_txs(const currency::acco // NOTE: stake coins return back to the wallet, newly generated coins go to miner_address (by default they are the same destinations) inline bool mine_next_pos_block_in_playtime_with_wallet(tools::wallet2& w, const currency::account_public_address& miner_address, size_t& pos_entries_count) { - tools::wallet2::mining_context ctx = AUTO_VAL_INIT(ctx); + tools::wallet2::mining_context ctx{}; w.fill_mining_context(ctx); if (!ctx.is_pos_allowed) return false; diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index b70070a8..d1a217c6 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -1218,7 +1218,9 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(tx_expiration_time_and_chain_switching); GENERATE_AND_PLAY(tx_key_image_pool_conflict); //GENERATE_AND_PLAY_HF(tx_version_against_hardfork, "4-*"); - GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "4-*"); + /* To execute the check of bare balance (function "check_tx_bare_balance") we need to run the test "tx_pool_semantic_validation" on the HF 3. By default behaviour bare outputs are disallowed on + the heights >= 10. */ + GENERATE_AND_PLAY_HF(tx_pool_semantic_validation, "3"); // Double spend GENERATE_AND_PLAY(gen_double_spend_in_tx); @@ -1297,8 +1299,10 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY_HF(eth_signed_asset_basics, "5-*"); // TODO: make HF4 version GENERATE_AND_PLAY_HF(eth_signed_asset_via_rpc, "5-*"); // TODO: make HF4 version //GENERATE_AND_PLAY_HF(asset_current_and_total_supplies_comparative_constraints, "4-*"); <-- temporary disabled, waiting for Stepan's fix -- sowle + GENERATE_AND_PLAY_HF(several_asset_emit_burn_txs_in_pool, "5-*"); GENERATE_AND_PLAY_HF(pos_fuse_test, "4-*"); + GENERATE_AND_PLAY_HF(wallet_reorganize_and_trim_test, "4-*"); diff --git a/tests/core_tests/cumulative_diificulty_adjustments_tests.cpp b/tests/core_tests/cumulative_diificulty_adjustments_tests.cpp index 35040e15..7e7c40b4 100644 --- a/tests/core_tests/cumulative_diificulty_adjustments_tests.cpp +++ b/tests/core_tests/cumulative_diificulty_adjustments_tests.cpp @@ -14,7 +14,7 @@ using namespace currency; cumulative_difficulty_adjustment_test::cumulative_difficulty_adjustment_test() { - epee::debug::get_set_enable_assert(true, true); + //epee::debug::get_set_enable_assert(true, true); REGISTER_CALLBACK_METHOD(cumulative_difficulty_adjustment_test, configure_core); REGISTER_CALLBACK_METHOD(cumulative_difficulty_adjustment_test, configure_check_height1); REGISTER_CALLBACK_METHOD(cumulative_difficulty_adjustment_test, memorize_main_chain); @@ -25,7 +25,7 @@ cumulative_difficulty_adjustment_test::cumulative_difficulty_adjustment_test() } cumulative_difficulty_adjustment_test::~cumulative_difficulty_adjustment_test() { - epee::debug::get_set_enable_assert(true, false); + //epee::debug::get_set_enable_assert(true, false); } #define FIRST_ALIAS_NAME "first" #define SECOND_ALIAS_NAME "second" diff --git a/tests/core_tests/escrow_wallet_altchain_test.cpp b/tests/core_tests/escrow_wallet_altchain_test.cpp index a59063c2..514ebc82 100644 --- a/tests/core_tests/escrow_wallet_altchain_test.cpp +++ b/tests/core_tests/escrow_wallet_altchain_test.cpp @@ -317,7 +317,8 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std alice_wlt->scan_tx_pool(stub); size_t blocks_fetched = 0; alice_wlt->refresh(blocks_fetched); - CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Alice got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected"); + //fetched blocks disabled since resync might happened on different situation and number of blocks_fetched might be unexpected + //CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Alice got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected"); LOG_PRINT_GREEN("Alice's transfers:" << ENDL << alice_wlt->dump_trunsfers(), LOG_LEVEL_1); if (se.a_balance != UINT64_MAX) { @@ -335,7 +336,8 @@ bool escrow_altchain_meta_impl::c1(currency::core& c, size_t ev_index, const std bob_wlt->scan_tx_pool(stub); blocks_fetched = 0; bob_wlt->refresh(blocks_fetched); - CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Bob got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected"); + //fetched blocks disabled since resync might happened on different situation and number of blocks_fetched might be unexpected + //CHECK_AND_ASSERT_MES(blocks_fetched == se.expected_blocks, false, "Bob got " << blocks_fetched << " after refresh, but " << se.expected_blocks << " is expected"); LOG_PRINT_GREEN("Bob's transfers:" << ENDL << bob_wlt->dump_trunsfers(), LOG_LEVEL_1); if (se.b_balance != UINT64_MAX) { diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index b4bfaca3..b511aaab 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -32,7 +32,7 @@ escrow_wallet_test::escrow_wallet_test() bool escrow_wallet_test::generate(std::vector& events) const { - epee::debug::get_set_enable_assert(true, true); + //epee::debug::get_set_enable_assert(true, true); currency::account_base genesis_acc; genesis_acc.generate(); @@ -47,7 +47,7 @@ bool escrow_wallet_test::generate(std::vector& events) const DO_CALLBACK(events, "c1"); - epee::debug::get_set_enable_assert(true, false); + //epee::debug::get_set_enable_assert(true, false); return true; } @@ -272,8 +272,8 @@ bool escrow_wallet_test::exec_test_with_cancel_release_type(currency::core& c, c bool escrow_wallet_test::c1(currency::core& c, size_t ev_index, const std::vector& events) { - epee::debug::get_set_enable_assert(true, true); - misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){epee::debug::get_set_enable_assert(true, false); }); + //epee::debug::get_set_enable_assert(true, true); + //misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){epee::debug::get_set_enable_assert(true, false); }); bool r = exec_test_with_cancel_release_type(c, events); if (!r) @@ -287,7 +287,7 @@ bool escrow_wallet_test::c1(currency::core& c, size_t ev_index, const std::vecto if (!r) return false; - epee::debug::get_set_enable_assert(true, false); + //epee::debug::get_set_enable_assert(true, false); return r; } @@ -780,7 +780,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st uint64_t alice_post_proposal_balance = alice_wlt->balance(); uint64_t alice_post_proposal_balance_expected = alice_start_balance - TESTS_DEFAULT_FEE; CHECK_AND_ASSERT_MES(alice_post_proposal_balance == alice_post_proposal_balance_expected, false, "Incorrect alice_post_proposal_balance: " << print_money(alice_post_proposal_balance) << ", expected: " << print_money(alice_post_proposal_balance_expected)); - std::deque transfers; + tools::transfer_container transfers; alice_wlt->get_transfers(transfers); CHECK_AND_ASSERT_MES(transfers.size() == 2 && ( (transfers[0].is_spent() && (transfers[1].m_flags & (WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION))) || @@ -2283,7 +2283,7 @@ bool escrow_proposal_not_enough_money::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(30), 0, MK_TEST_COINS(30), 0, 0), false, ""); - std::deque transfers; + tools::transfer_container transfers; alice_wlt->get_transfers(transfers); CHECK_AND_ASSERT_MES(transfers.size() == 1, false, "Incorrect transfers size: " << transfers.size()); diff --git a/tests/core_tests/isolate_auditable_and_proof.cpp b/tests/core_tests/isolate_auditable_and_proof.cpp index b363ba12..f676c8a1 100644 --- a/tests/core_tests/isolate_auditable_and_proof.cpp +++ b/tests/core_tests/isolate_auditable_and_proof.cpp @@ -32,7 +32,7 @@ bool isolate_auditable_and_proof::generate(std::vector& events test_core_time::adjust(m_genesis_timestamp); - epee::debug::get_set_enable_assert(true, true); + //epee::debug::get_set_enable_assert(true, true); currency::account_base genesis_acc; genesis_acc.generate(); @@ -47,7 +47,7 @@ bool isolate_auditable_and_proof::generate(std::vector& events REWIND_BLOCKS_N(events, blk_0r, blk_0, m_mining_accunt, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 15); DO_CALLBACK(events, "c1"); - epee::debug::get_set_enable_assert(true, false); + //epee::debug::get_set_enable_assert(true, false); return true; } @@ -61,8 +61,8 @@ bool isolate_auditable_and_proof::configure_core(currency::core& c, size_t ev_in bool isolate_auditable_and_proof::c1(currency::core& c, size_t ev_index, const std::vector& events) { - epee::debug::get_set_enable_assert(true, true); - misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){epee::debug::get_set_enable_assert(true, false); }); + //epee::debug::get_set_enable_assert(true, true); + //misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler([&](){epee::debug::get_set_enable_assert(true, false); }); LOG_PRINT_MAGENTA("Mining Address: " << currency::get_account_address_as_str(m_mining_accunt.get_public_address()), LOG_LEVEL_0); diff --git a/tests/core_tests/multiassets_test.cpp b/tests/core_tests/multiassets_test.cpp index ddf9a1fe..c7b13844 100644 --- a/tests/core_tests/multiassets_test.cpp +++ b/tests/core_tests/multiassets_test.cpp @@ -310,10 +310,19 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v //miner_wlt->refresh(); + // check emit_asset() with modified 'current_supply' miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT([&](const wde_construct_tx_handle_asset_descriptor_operation_before_seal& o) { - o.pado->descriptor.current_supply += 1000000; + if(o.pado->version < ASSET_DESCRIPTOR_OPERATION_HF5_VER) + { + //hf4 + o.pado->opt_descriptor->current_supply += 1000000; + } + else + { + *o.pado->opt_amount += 1000000; + } }); //test emit function but re-adjust current_supply to wrong amount r = false; @@ -345,7 +354,15 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v 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; + if (o.pado->version < ASSET_DESCRIPTOR_OPERATION_HF5_VER) + { + //hf4 + o.pado->opt_descriptor->current_supply -= 1000000; + } + else + { + *o.pado->opt_amount -= 1000000; + } }); @@ -407,6 +424,31 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v } //------------------------------------------------------------------------------ +//@#@ TODO: subject for refactoring: this fill_ado*/fill_adb* are copy/paste clones of wallet's, need to be implemented in one place at some point +//---------------------------------------------------------------------------------------------------- +void fill_ado_version_based_onhardfork(currency::asset_descriptor_operation& asset_reg_info, size_t current_latest_hf) +{ + if (current_latest_hf < ZANO_HARDFORK_05) + { + asset_reg_info.version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; + } + else + { + asset_reg_info.version = ASSET_DESCRIPTOR_OPERATION_LAST_VER; + } +} +//---------------------------------------------------------------------------------------------------- +void fill_adb_version_based_onhardfork(currency::asset_descriptor_base& asset_base, size_t current_latest_hf) +{ + if (current_latest_hf < ZANO_HARDFORK_05) + { + asset_base.version = ASSET_DESCRIPTOR_BASE_HF4_VER; + } + else + { + asset_base.version = ASSET_DESCRIPTOR_BASE_LAST_VER; + } +} assets_and_explicit_native_coins_in_outs::assets_and_explicit_native_coins_in_outs() { @@ -535,7 +577,7 @@ bool assets_and_explicit_native_coins_in_outs::c2_alice_deploys_asset(currency:: // make sure Alice has two UTXO now tools::transfer_container transfers{}; alice_wlt->get_transfers(transfers); - size_t unspent_transfers = std::count_if(transfers.begin(), transfers.end(), [](const tools::transfer_details& tr){ return !tr.is_spent(); }); + size_t unspent_transfers = std::count_if(transfers.begin(), transfers.end(), [](const auto& tr){ return !tr.second.is_spent(); }); CHECK_AND_ASSERT_MES(unspent_transfers == 2, false, "unexpected number of Alice's unspent transfers: " << unspent_transfers); asset_descriptor_base adb{}; @@ -694,15 +736,15 @@ bool asset_depoyment_and_few_zc_utxos::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", m_alice_initial_balance, 0, m_alice_initial_balance, 0, 0), false, ""); // make sure Alice has correct UTXO wallet structure - tools::transfer_container transfers{}; + tools::transfer_container transfers; alice_wlt->get_transfers(transfers); size_t zc_unspent_outs = 0, unspent_outs = 0; for(auto& td : transfers) { - if (!td.is_spent()) + if (!td.second.is_spent()) { ++unspent_outs; - if (td.is_zc()) + if (td.second.is_zc()) ++zc_unspent_outs; } } @@ -858,7 +900,7 @@ bool asset_emission_and_unconfirmed_balance::c1(currency::core& c, size_t ev_ind asset_descriptor_base adb{}; adb.total_max_supply = UINT64_MAX; - adb.full_name = "2**64"; + adb.full_name = "2 xx 64"; adb.ticker = "2POWER64"; std::vector destinations; @@ -894,6 +936,7 @@ bool asset_emission_and_unconfirmed_balance::c1(currency::core& c, size_t ev_ind asset_operation_and_hardfork_checks::asset_operation_and_hardfork_checks() { + m_adb_hello.version = ASSET_DESCRIPTOR_BASE_HF4_VER; m_adb_hello.total_max_supply = 1'000'000'000'000'000'000; m_adb_hello.current_supply = 1'000'000'000'000'000'000; m_adb_hello.ticker = "HLO"; @@ -903,6 +946,7 @@ asset_operation_and_hardfork_checks::asset_operation_and_hardfork_checks() m_ado_hello.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; m_ado_hello.opt_asset_id = currency::null_pkey; + m_ado_hello.version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; m_adb_bye.total_max_supply = 1'000'000'000'000'000'000; m_adb_bye.current_supply = 1'000'000'000'000'000'000; @@ -913,6 +957,7 @@ asset_operation_and_hardfork_checks::asset_operation_and_hardfork_checks() m_ado_bye.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; m_ado_hello.opt_asset_id = currency::null_pkey; + m_ado_hello.version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; REGISTER_CALLBACK_METHOD(asset_operation_and_hardfork_checks, c1); REGISTER_CALLBACK_METHOD(asset_operation_and_hardfork_checks, c2); @@ -942,10 +987,10 @@ bool asset_operation_and_hardfork_checks::generate( alice.generate(); m_adb_hello.owner = alice.get_public_address().spend_public_key; - m_ado_hello.descriptor = m_adb_hello; + m_ado_hello.opt_descriptor = m_adb_hello; m_adb_bye.owner = alice.get_public_address().spend_public_key; - m_ado_bye.descriptor = m_adb_bye; + m_ado_bye.opt_descriptor = m_adb_bye; MAKE_GENESIS_BLOCK(events, blk_0, @@ -1014,7 +1059,9 @@ bool asset_operation_and_hardfork_checks::generate( /* asset_id = */ currency::null_pkey); tx_version = get_tx_version(get_block_height(blk_1r), m_hardforks); - + size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_1r)); + fill_ado_version_based_onhardfork(m_ado_hello, hf_n); + fill_adb_version_based_onhardfork(*m_ado_hello.opt_descriptor, hf_n); success = construct_tx(alice.get_keys(), sources, destinations, @@ -1061,6 +1108,9 @@ bool asset_operation_and_hardfork_checks::generate( tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); + hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + fill_ado_version_based_onhardfork(m_ado_hello, hf_n); + fill_adb_version_based_onhardfork(*m_ado_hello.opt_descriptor, hf_n); success = construct_tx(alice.get_keys(), sources, destinations, @@ -1099,6 +1149,10 @@ bool asset_operation_and_hardfork_checks::generate( tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); + hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + fill_ado_version_based_onhardfork(m_ado_bye, hf_n); + fill_adb_version_based_onhardfork(*m_ado_bye.opt_descriptor, hf_n); + success = construct_tx(alice.get_keys(), sources, destinations, @@ -1134,6 +1188,10 @@ bool asset_operation_and_hardfork_checks::generate( tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); + hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + fill_ado_version_based_onhardfork(m_ado_bye, hf_n); + fill_adb_version_based_onhardfork(*m_ado_bye.opt_descriptor, hf_n); + success = construct_tx(alice.get_keys(), sources, destinations, @@ -1212,6 +1270,7 @@ bool asset_operation_and_hardfork_checks::c2( asset_operation_in_consolidated_tx::asset_operation_in_consolidated_tx() { + m_adb_alice_currency.version = ASSET_DESCRIPTOR_BASE_HF4_VER; m_adb_alice_currency.total_max_supply = 1'000'000'000'000'000'000; m_adb_alice_currency.current_supply = 1'000'000'000'000'000'000; m_adb_alice_currency.ticker = "ALC"; @@ -1221,6 +1280,7 @@ asset_operation_in_consolidated_tx::asset_operation_in_consolidated_tx() m_ado_alice_currency.operation_type = ASSET_DESCRIPTOR_OPERATION_REGISTER; m_ado_alice_currency.opt_asset_id = currency::null_pkey; + m_ado_alice_currency.version = ASSET_DESCRIPTOR_OPERATION_HF4_VER; REGISTER_CALLBACK_METHOD(asset_operation_in_consolidated_tx, assert_balances); REGISTER_CALLBACK_METHOD(asset_operation_in_consolidated_tx, assert_alice_currency_not_registered); @@ -1242,7 +1302,7 @@ bool asset_operation_in_consolidated_tx::generate(std::vector& m_accounts.push_back(alice); m_accounts.push_back(bob); m_adb_alice_currency.owner = m_accounts.at(ALICE_ACC_IDX).get_public_address().spend_public_key; - m_ado_alice_currency.descriptor = m_adb_alice_currency; + m_ado_alice_currency.opt_descriptor = m_adb_alice_currency; MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); DO_CALLBACK(events, "configure_core"); @@ -1288,6 +1348,11 @@ bool asset_operation_in_consolidated_tx::generate(std::vector& destinations.emplace_back(MK_TEST_COINS(/* 10 - 5 - 0 = */ 5), bob.get_public_address()); destinations.emplace_back(m_adb_alice_currency.current_supply, alice.get_public_address(), null_pkey); tx_version = get_tx_version(get_block_height(blk_2r), m_hardforks); + size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + fill_ado_version_based_onhardfork(m_ado_alice_currency, hf_n); + fill_adb_version_based_onhardfork(*m_ado_alice_currency.opt_descriptor, hf_n); + + success = construct_tx(bob.get_keys(), sources, destinations, { m_ado_alice_currency }, empty_attachment, tx_2, tx_version, one_time, 0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, /* fee = */ 0, context_tx_2); CHECK_AND_ASSERT_MES(success, false, "failed to construct transaction tx_2 on step 2"); @@ -1348,7 +1413,6 @@ bool eth_signed_asset_basics::generate(std::vector& events) co m_accounts.resize(TOTAL_ACCS_COUNT); account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts); account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts); - miner_acc.generate(); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks @@ -1423,7 +1487,9 @@ bool eth_signed_asset_basics::c1(currency::core& c, size_t ev_index, const std:: crypto::eth_signature eth_sig{}; r = crypto::generate_eth_signature(ft.tx_id, eth_sk, eth_sig); CHECK_AND_ASSERT_MES(r, false, "generate_eth_signature failed"); - + r = crypto::verify_eth_signature(ft.tx_id, eth_pk, eth_sig); + CHECK_AND_ASSERT_MES(r, false, "generate_eth_signature self validation failed"); + transaction emit_tx{}; bool transfers_unlocked = false; miner_wlt->submit_externally_signed_asset_tx(ft, eth_sig, true, emit_tx, transfers_unlocked); @@ -1560,7 +1626,6 @@ bool eth_signed_asset_via_rpc::generate(std::vector& events) c account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts); account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts); account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts); - miner_acc.generate(); MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks @@ -1805,8 +1870,8 @@ bool eth_signed_asset_via_rpc::c1(currency::core& c, size_t ev_index, const std: CHECK_AND_ASSERT_EQ(pado->operation_type, ASSET_DESCRIPTOR_OPERATION_UPDATE); CHECK_AND_ASSERT_EQ(pado->opt_asset_id.has_value(), true); CHECK_AND_ASSERT_EQ(pado->opt_asset_id.get(), asset_id); - CHECK_AND_ASSERT_EQ(pado->descriptor.owner_eth_pub_key.has_value(), true); - CHECK_AND_ASSERT_EQ(pado->descriptor.owner_eth_pub_key.get(), eth_pk_2); // the most important condition for an ownership transfer + CHECK_AND_ASSERT_EQ(pado->opt_descriptor->owner_eth_pub_key.has_value(), true); + CHECK_AND_ASSERT_EQ(pado->opt_descriptor->owner_eth_pub_key.get(), eth_pk_2); // the most important condition for an ownership transfer // other fileds of pado->descriptor may also be checked here // @@ -2007,12 +2072,13 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec m_accounts.push_back(miner); m_accounts.push_back(alice); m_adbs.at(asset_position::alpha).owner = m_adbs.at(asset_position::beta).owner = m_adbs.at(asset_position::gamma).owner = alice.get_public_address().spend_public_key; - m_ados_register.at(asset_position::alpha).descriptor = m_adbs.at(asset_position::alpha); - m_ados_register.at(asset_position::beta).descriptor = m_ado_emit.descriptor = m_adbs.at(asset_position::beta); - m_ados_register.at(asset_position::gamma).descriptor = m_adbs.at(asset_position::gamma); - CHECK_AND_ASSERT(m_ado_emit.descriptor.current_supply <= m_ado_emit.descriptor.total_max_supply, false); - ++m_ado_emit.descriptor.current_supply; - CHECK_AND_ASSERT(m_ado_emit.descriptor.current_supply > m_ado_emit.descriptor.total_max_supply, false); + m_ados_register.at(asset_position::alpha).opt_descriptor = m_adbs.at(asset_position::alpha); + m_ados_register.at(asset_position::beta).opt_descriptor = m_ado_emit.opt_descriptor = m_adbs.at(asset_position::beta); + m_ados_register.at(asset_position::gamma).opt_descriptor = m_adbs.at(asset_position::gamma); + + CHECK_AND_ASSERT((*m_ado_emit.opt_descriptor).current_supply <= (*m_ado_emit.opt_descriptor).total_max_supply, false); + ++(m_ado_emit.opt_descriptor->current_supply); + CHECK_AND_ASSERT(m_ado_emit.opt_descriptor->current_supply > m_ado_emit.opt_descriptor->total_max_supply, false); MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); DO_CALLBACK(events, "configure_core"); @@ -2040,12 +2106,15 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec std::vector destinations{}; const auto& ado{m_ados_register.at(asset_position::gamma)}; crypto::secret_key one_time{}; + size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_1r)); + //fill_ado_version_based_onhardfork(ado, hf_n); + //fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n); success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_EQ(success, true); - destinations.emplace_back(ado.descriptor.current_supply, alice.get_public_address(), null_pkey); - CHECK_AND_ASSERT_EQ(ado.descriptor.total_max_supply, 0); - CHECK_AND_ASSERT_EQ(ado.descriptor.total_max_supply, ado.descriptor.current_supply); + destinations.emplace_back(ado.opt_descriptor->current_supply, alice.get_public_address(), null_pkey); + CHECK_AND_ASSERT_EQ(ado.opt_descriptor->total_max_supply, 0); + CHECK_AND_ASSERT_EQ(ado.opt_descriptor->total_max_supply, ado.opt_descriptor->current_supply); success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_1, get_tx_version(get_block_height(top), m_hardforks), one_time, 0); CHECK_AND_ASSERT_EQ(success, true); } @@ -2063,11 +2132,14 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec std::vector destinations{}; crypto::secret_key one_time{}; const auto& ado{m_ados_register.at(asset_position::alpha)}; + size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + //fill_ado_version_based_onhardfork(ado, hf_n); + //fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n); success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_EQ(success, true); - destinations.emplace_back(ado.descriptor.current_supply, alice.get_public_address(), null_pkey); - CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > ado.descriptor.total_max_supply, false, "current_supply <= total_max_supply"); + destinations.emplace_back(ado.opt_descriptor->current_supply, alice.get_public_address(), null_pkey); + CHECK_AND_ASSERT_MES(ado.opt_descriptor->current_supply > ado.opt_descriptor->total_max_supply, false, "current_supply <= total_max_supply"); success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_2, get_tx_version(get_block_height(top), m_hardforks), one_time, 0); CHECK_AND_ASSERT_EQ(success, true); } @@ -2085,11 +2157,14 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec std::vector destinations{}; crypto::secret_key one_time{}; const auto& ado{m_ados_register.at(asset_position::beta)}; + size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_2r)); + //fill_ado_version_based_onhardfork(ado, hf_n); + //fill_adb_version_based_onhardfork(*ado.opt_descriptor, hf_n); success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_EQ(success, true); - destinations.emplace_back(ado.descriptor.current_supply, alice.get_public_address(), null_pkey); - CHECK_AND_ASSERT(ado.descriptor.current_supply <= ado.descriptor.total_max_supply, false); + destinations.emplace_back(ado.opt_descriptor->current_supply, alice.get_public_address(), null_pkey); + CHECK_AND_ASSERT(ado.opt_descriptor->current_supply <= ado.opt_descriptor->total_max_supply, false); success = construct_tx(alice.get_keys(), sources, destinations, {ado}, empty_attachment, tx_3, get_tx_version(get_block_height(top), m_hardforks), one_time, 0); CHECK_AND_ASSERT_EQ(success, true); } @@ -2108,7 +2183,7 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec m_ado_emit.opt_asset_id = beta_asset_id; } - CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, m_ado_emit.descriptor.total_max_supply); + CHECK_AND_ASSERT_GREATER(m_ado_emit.opt_descriptor->current_supply, m_ado_emit.opt_descriptor->total_max_supply); // Alice emits asset BETA. The emission is performed through the wallet object. There is no emission, because .current_supply > .total_max_supply in the asset base descriptor. DO_CALLBACK(events, "emit_asset_beta_with_incorrect_supply"); @@ -2123,18 +2198,25 @@ bool asset_current_and_total_supplies_comparative_constraints::generate(std::vec tx_source_entry source{}; finalize_tx_param ftp{}; finalized_tx ftx{}; + + size_t hf_n = m_hardforks.get_the_most_recent_hardfork_id_for_height(get_block_height(blk_3r)); + //fill_ado_version_based_onhardfork(ado_register, hf_n); + //fill_adb_version_based_onhardfork(*ado_register.opt_descriptor, hf_n); success = fill_tx_sources_and_destinations(events, top, alice.get_keys(), alice.get_public_address(), MK_TEST_COINS(2), TESTS_DEFAULT_FEE, 0, sources, destinations); CHECK_AND_ASSERT_EQ(success, true); - CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, ado_register.descriptor.current_supply); - destinations.emplace_back(m_ado_emit.descriptor.current_supply - ado_register.descriptor.current_supply, alice.get_public_address(), null_pkey); + CHECK_AND_ASSERT_GREATER(m_ado_emit.opt_descriptor->current_supply, ado_register.opt_descriptor->current_supply); + destinations.emplace_back(m_ado_emit.opt_descriptor->current_supply - ado_register.opt_descriptor->current_supply, alice.get_public_address(), null_pkey); + + fill_ado_version_based_onhardfork(m_ado_emit, hf_n); + if (m_ado_emit.opt_descriptor.has_value()) fill_adb_version_based_onhardfork(*m_ado_emit.opt_descriptor, hf_n); ftp.sources = sources; ftp.prepared_destinations = destinations; ftp.tx_version = get_tx_version(get_block_height(top), m_hardforks); ftp.extra = {m_ado_emit}; ftp.shuffle = true; - CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, m_ado_emit.descriptor.total_max_supply); + CHECK_AND_ASSERT_GREATER(m_ado_emit.opt_descriptor->current_supply, m_ado_emit.opt_descriptor->total_max_supply); success = construct_tx(alice.get_keys(), ftp, ftx); CHECK_AND_ASSERT_EQ(success, true); tx_4 = ftx.tx; @@ -2153,7 +2235,7 @@ bool asset_current_and_total_supplies_comparative_constraints::assert_asset_alph { const std::shared_ptr alice_wallet{init_playtime_test_wallet_t(events, c, ALICE_ACC_IDX)}; crypto::public_key alpha_asset_id{}; - const std::string ticker{m_ados_register.at(asset_position::alpha).descriptor.ticker}; + const std::string ticker{m_ados_register.at(asset_position::alpha).opt_descriptor->ticker}; alice_wallet->refresh(); @@ -2176,7 +2258,7 @@ bool asset_current_and_total_supplies_comparative_constraints::assert_asset_beta { const std::shared_ptr alice_wallet{init_playtime_test_wallet_t(events, c, ALICE_ACC_IDX)}; crypto::public_key key_beta_asset_id{}; - const std::string ticker{m_ados_register.at(asset_position::beta).descriptor.ticker}; + const std::string ticker{m_ados_register.at(asset_position::beta).opt_descriptor->ticker}; alice_wallet->refresh(); @@ -2220,11 +2302,11 @@ bool asset_current_and_total_supplies_comparative_constraints::emit_asset_beta_w { const auto& ado_register{m_ados_register.at(asset_position::beta)}; - CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, ado_register.descriptor.current_supply); - destinations.emplace_back(m_ado_emit.descriptor.current_supply - ado_register.descriptor.current_supply, alice_wallet->get_account().get_public_address(), beta_asset_id); + CHECK_AND_ASSERT_GREATER(m_ado_emit.opt_descriptor->current_supply, ado_register.opt_descriptor->current_supply); + destinations.emplace_back(m_ado_emit.opt_descriptor->current_supply - ado_register.opt_descriptor->current_supply, alice_wallet->get_account().get_public_address(), beta_asset_id); } - CHECK_AND_ASSERT_GREATER(m_ado_emit.descriptor.current_supply, m_ado_emit.descriptor.total_max_supply); + CHECK_AND_ASSERT_GREATER(m_ado_emit.opt_descriptor->current_supply, m_ado_emit.opt_descriptor->total_max_supply); try { @@ -2260,10 +2342,11 @@ bool asset_current_and_total_supplies_comparative_constraints::assert_asset_beta } { - const uint64_t& current_supply{register_ado.descriptor.current_supply}; + const uint64_t& current_supply{register_ado.opt_descriptor->current_supply}; - CHECK_AND_ASSERT_MES(alice_wallet->balance(beta_asset_id) == current_supply, false, "Alice has got not exactly " + std::to_string(current_supply) + ' ' + register_ado.descriptor.ticker); + CHECK_AND_ASSERT_MES(alice_wallet->balance(beta_asset_id) == current_supply, false, "Alice has got not exactly " + std::to_string(current_supply) + ' ' + register_ado.opt_descriptor->ticker); } + return true; } bool asset_current_and_total_supplies_comparative_constraints::public_burn_asset_beta_with_incorrect_supply(currency::core& c, size_t ev_index, const std::vector& events) const @@ -2283,7 +2366,7 @@ bool asset_current_and_total_supplies_comparative_constraints::public_burn_asset { transaction tx{}; - alice_wallet->burn_asset(beta_asset_id, m_ado_emit.descriptor.current_supply, tx); + alice_wallet->burn_asset(beta_asset_id, m_ado_emit.opt_descriptor->current_supply, tx); } catch (const std::runtime_error&) { @@ -2298,7 +2381,7 @@ bool asset_current_and_total_supplies_comparative_constraints::assert_asset_gamm { const std::shared_ptr alice_wallet{init_playtime_test_wallet_t(events, c, ALICE_ACC_IDX)}; crypto::public_key key_gamma_asset_id{}; - const std::string ticker{m_ados_register.at(asset_position::gamma).descriptor.ticker}; + const std::string ticker{m_ados_register.at(asset_position::gamma).opt_descriptor->ticker}; alice_wallet->refresh(); @@ -2314,7 +2397,189 @@ bool asset_current_and_total_supplies_comparative_constraints::assert_asset_gamm CHECK_AND_ASSERT_MES(c.get_blockchain_storage().get_asset_info(key_gamma_asset_id, gamma_adb), false, "the asset " + ticker + " must be registered"); } - CHECK_AND_ASSERT_EQ(alice_wallet->balance(key_gamma_asset_id), m_ados_register.at(asset_position::gamma).descriptor.current_supply); + CHECK_AND_ASSERT_EQ(alice_wallet->balance(key_gamma_asset_id), m_ados_register.at(asset_position::gamma).opt_descriptor->current_supply); + + return true; +} + +//------------------------------------------------------------------------------ + +several_asset_emit_burn_txs_in_pool::several_asset_emit_burn_txs_in_pool() +{ + REGISTER_CALLBACK_METHOD(several_asset_emit_burn_txs_in_pool, c1); +} + +bool several_asset_emit_burn_txs_in_pool::generate(std::vector& events) const +{ + // + // Test idea: make sure two asset emit or two asset burn tx can be added to the pool for the same asset. + // + uint64_t ts = test_core_time::get_time(); + m_accounts.resize(TOTAL_ACCS_COUNT); + account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts); + account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts); + + MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts); + // rebuild genesis miner tx + std::vector destinations; + destinations.emplace_back(MK_TEST_COINS(1), alice_acc.get_public_address()); + destinations.emplace_back(MK_TEST_COINS(1), alice_acc.get_public_address()); + CHECK_AND_ASSERT_MES(replace_coinbase_in_genesis_block(destinations, generator, events, blk_0), false, ""); // leftover amount will be also send to miner + + DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks + REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3); + + DO_CALLBACK(events, "c1"); + + return true; +} + +bool several_asset_emit_burn_txs_in_pool::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + bool r = false; + + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX); + miner_wlt->refresh(); + std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX); + alice_wlt->refresh(); + + // asset description + asset_descriptor_base adb{}; + adb.decimal_point = 3; + adb.total_max_supply = 10'000; + adb.full_name = "Lets gooo!"; + adb.ticker = "BRNDN"; + + uint64_t initial_register_amount = 5'000; + + // 1. Miner registers an asset and sends some initial amount to Alice + std::vector destinations; + destinations.emplace_back(initial_register_amount, m_accounts[ALICE_ACC_IDX].get_public_address(), null_pkey); + finalized_tx ft{}; + crypto::public_key asset_id{}; + miner_wlt->deploy_new_asset(adb, destinations, ft, asset_id); + LOG_PRINT_GREEN_L0("Asset " << asset_id << " was successfully deployed with tx " << ft.tx_id); + + // make sure tx was added to the pool, then mine a block to confirm it + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, ""); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + size_t blocks_fetched = 0; + miner_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 1); + + // Alice checks her asset balance + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 1); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", initial_register_amount, asset_id, adb.decimal_point), false, ""); + + + // + // 2. Miner emits additional amount of the asset in two transactions (all goes to Alice) + // + + // 2.1 the first emit + uint64_t additional_emit_amount = 2'500; + uint64_t total_asset_amount = initial_register_amount + additional_emit_amount; + + destinations.clear(); + destinations.emplace_back(additional_emit_amount, m_accounts[ALICE_ACC_IDX].get_public_address(), null_pkey); + ft = finalized_tx{}; + miner_wlt->emit_asset(asset_id, destinations, ft); + + // make sure tx was added to the pool + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + // Alice checks her asset balance (including unconfirmed txs) + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 0); + bool stub{}; + alice_wlt->scan_tx_pool(stub); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", total_asset_amount, asset_id, adb.decimal_point), false, ""); + + // 2.2 the second emit + additional_emit_amount = 2'500; + total_asset_amount += additional_emit_amount; + + destinations.clear(); + destinations.emplace_back(additional_emit_amount, m_accounts[ALICE_ACC_IDX].get_public_address(), null_pkey); + ft = finalized_tx{}; + miner_wlt->emit_asset(asset_id, destinations, ft); + + // make sure the second tx was added to the pool + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + // Alice checks her asset balance (including unconfirmed txs) + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 0); + alice_wlt->scan_tx_pool(stub); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", total_asset_amount, asset_id, adb.decimal_point), false, ""); + + // 2.3 + // mine a block to confirm both txs to make sure everything is alright + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, ""); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 1); + + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", total_asset_amount, asset_id, adb.decimal_point), false, ""); + + + // make sure these txs are fully confirmed + CHECK_AND_ASSERT_MES(mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW), false, ""); + + + // + // 3. Alice burns amount of the asset in two transactions + // + alice_wlt->refresh(); + + // 3.1, the first burn + uint64_t burn_amount = 2'500; + total_asset_amount -= burn_amount; + + ft = finalized_tx{}; + alice_wlt->burn_asset(asset_id, burn_amount, ft); + + // make sure tx was added to the pool + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 0); + alice_wlt->scan_tx_pool(stub); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", total_asset_amount, asset_id, adb.decimal_point), false, ""); + + // 3.2, the second burn + burn_amount = 2'500; + total_asset_amount -= burn_amount; + + ft = finalized_tx{}; + alice_wlt->burn_asset(asset_id, burn_amount, ft); + + // make sure both txs are now in the pool + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 0); + alice_wlt->scan_tx_pool(stub); + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", total_asset_amount, asset_id, adb.decimal_point), false, ""); + + // 3.3 + // mine a block to confirm both txs to make sure everything is alright + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, ""); + CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); + + alice_wlt->refresh(blocks_fetched); + CHECK_AND_ASSERT_EQ(blocks_fetched, 1); + + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", total_asset_amount, asset_id, adb.decimal_point), false, ""); + + // make sure these txs are fully confirmed + CHECK_AND_ASSERT_MES(mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW), false, ""); + + CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt, "Alice", total_asset_amount, asset_id, adb.decimal_point), false, ""); return true; } diff --git a/tests/core_tests/multiassets_test.h b/tests/core_tests/multiassets_test.h index c82e00f3..d306a0f4 100644 --- a/tests/core_tests/multiassets_test.h +++ b/tests/core_tests/multiassets_test.h @@ -114,3 +114,10 @@ private: mutable std::array m_ados_register{}; mutable currency::asset_descriptor_operation m_ado_emit{}; }; + +struct several_asset_emit_burn_txs_in_pool : public wallet_test +{ + several_asset_emit_burn_txs_in_pool(); + 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/multisig_wallet_tests.cpp b/tests/core_tests/multisig_wallet_tests.cpp index 2801b1fc..ef4f0c34 100644 --- a/tests/core_tests/multisig_wallet_tests.cpp +++ b/tests/core_tests/multisig_wallet_tests.cpp @@ -2571,7 +2571,7 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co LOG_PRINT_YELLOW("%%%%% tx " << get_transaction_hash(tx) << " is spending multisig output " << multisig_id, LOG_LEVEL_0); bool stub; - std::deque transfers; + tools::transfer_container transfers; std::vector unconfirmed_transfers; alice_wlt->scan_tx_pool(stub); diff --git a/tests/core_tests/pos_block_builder.cpp b/tests/core_tests/pos_block_builder.cpp index 62561121..da3e08c1 100644 --- a/tests/core_tests/pos_block_builder.cpp +++ b/tests/core_tests/pos_block_builder.cpp @@ -282,7 +282,7 @@ void pos_block_builder::step5_sign(const currency::tx_source_entry& se, const cu // range proofs currency::zc_outs_range_proof range_proofs{}; - r = generate_zc_outs_range_proof(miner_tx_id, 0, m_miner_tx_tgc, m_block.miner_tx.vout, range_proofs); + r = generate_zc_outs_range_proof(miner_tx_id, m_miner_tx_tgc, m_block.miner_tx.vout, range_proofs); CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate zc_outs_range_proof()"); m_block.miner_tx.proofs.emplace_back(std::move(range_proofs)); diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index f82c3a10..14b3db62 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -1711,7 +1711,6 @@ bool tx_pool_semantic_validation::generate(std::vector& events MAKE_GENESIS_BLOCK(events, blk_0, miner, test_core_time::get_time()); DO_CALLBACK(events, "configure_core"); - CHECK_AND_ASSERT_EQ(validate_tx_semantic(transaction{}, CURRENCY_MAX_TRANSACTION_BLOB_SIZE), false); // No inputs. @@ -1728,7 +1727,7 @@ bool tx_pool_semantic_validation::generate(std::vector& events { transaction tx{}; - tx.vin.emplace_back(); + tx.vin.emplace_back(txin_gen{}); CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); DO_CALLBACK(events, "mark_invalid_tx"); ADD_CUSTOM_EVENT(events, tx); @@ -1750,7 +1749,6 @@ bool tx_pool_semantic_validation::generate(std::vector& events point_t point_public_key{}; txout_to_key target{}; std::array inputs{}; - tx_out_bare output{}; transaction tx{}; CHECK_AND_ASSERT_EQ(point_public_key.from_string("499790c3302b9f0514e2db09b390679283d43d971383d33dc24c7991ea4cf6d7"), true); @@ -1763,10 +1761,6 @@ bool tx_pool_semantic_validation::generate(std::vector& events tx.vin.push_back(input); } - output.amount = 1; - output.target = target; - tx.vout.push_back(output); - CHECK_AND_ASSERT_GREATER(inputs.at(0).amount, inputs.at(0).amount + inputs.at(1).amount); CHECK_AND_ASSERT_GREATER(inputs.at(1).amount, inputs.at(0).amount + inputs.at(1).amount); CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); @@ -1803,41 +1797,50 @@ bool tx_pool_semantic_validation::generate(std::vector& events // Equal key images in inputs. { - tx_out_bare output; transaction tx{}; - std::array inputs{}; - point_t key_image_point{}; - key_image image{}; - output.amount = 1; - tx.vout.push_back(output); - CHECK_AND_ASSERT_EQ(key_image_point.from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true); - image = key_image_point.to_key_image(); - - for (int position{}; position < 2; ++position) { - inputs.at(position).k_image = image; - tx.vin.push_back(inputs.at(position)); + txin_zc_input input_zc{}; + txin_htlc input_htlc{}; + txin_to_key input_to_key{}; + point_t point_key_image{}; + + CHECK_AND_ASSERT_EQ(point_key_image.from_string("93fa59f43fb9cff98e6867d20cf200c98b29cae406acdbde798ffb3e30d3503a"), true); + input_zc.k_image = point_key_image.to_key_image(); + CHECK_AND_ASSERT_EQ(point_key_image.from_string("ad1226e3fd1be15e26b119fa80380e580a498e5fa3421b63fded89672b526a44"), true); + input_htlc.k_image = point_key_image.to_key_image(); + CHECK_AND_ASSERT_EQ(point_key_image.from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true); + input_to_key.k_image = point_key_image.to_key_image(); + tx.vin.push_back(input_zc); + tx.vin.push_back(input_htlc); + tx.vin.push_back(input_to_key); } - CHECK_AND_ASSERT_EQ(tx.vin.at(0).type(), typeid(txin_to_key)); - CHECK_AND_ASSERT_EQ(tx.vin.at(0).type(), tx.vin.at(1).type()); - CHECK_AND_ASSERT_EQ(boost::get(tx.vin.at(0)).k_image, boost::get(tx.vin.at(1)).k_image); - CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); - DO_CALLBACK(events, "mark_invalid_tx"); - ADD_CUSTOM_EVENT(events, tx); + { + txin_to_key input{}; + + input.amount = 0; + tx.vin.push_back(input); + } + + for (int8_t step{}; step < 3; ++step) + { + tx.vin.push_back(tx.vin.front()); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + tx.vin.erase(tx.vin.begin(), tx.vin.begin() + 1); + } + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); } // Two entries of the same type in extra. { - tx_out_bare output; transaction tx{}; std::array inputs{}; std::array key_image_points{}; - key_image image{}; - output.amount = 1; - tx.vout.push_back(output); CHECK_AND_ASSERT_EQ(key_image_points.at(0).from_string("de3c22a62f15e6de8abe6b217085b2aead196daf5ddd67d9c4b366330736fbeb"), true); CHECK_AND_ASSERT_EQ(key_image_points.at(1).from_string("9f3eef913921ca35239e696725595e3686bb0d69e3e805791c5aa93d5754aa5c"), true); @@ -1859,8 +1862,8 @@ bool tx_pool_semantic_validation::generate(std::vector& events // tx.version <= TRANSACTION_VERSION_PRE_HF4. Balance check fail: sum of inputs <= sum of outputs. { + tx_out_bare output{}; transaction tx{}; - tx_out_bare output; std::array key_image_points{}; std::array inputs{}; @@ -1879,7 +1882,10 @@ bool tx_pool_semantic_validation::generate(std::vector& events tx.vin.push_back(input); } - CHECK_AND_ASSERT_GREATER(output.amount, std::accumulate(inputs.begin(), inputs.end(), std::uint64_t{}, [](uint64_t sum, const txin_to_key& input) { return sum + input.amount; })); + const uint64_t sum_inputs{std::accumulate(inputs.begin(), inputs.end(), std::uint64_t{}, [](uint64_t sum, const txin_to_key& input) { return sum + input.amount; })}; + + CHECK_AND_ASSERT_LESS(sum_inputs, output.amount); + CHECK_AND_ASSERT_EQ(output.amount - sum_inputs, 1); CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); DO_CALLBACK(events, "mark_invalid_tx"); ADD_CUSTOM_EVENT(events, tx); @@ -1911,5 +1917,207 @@ bool tx_pool_semantic_validation::generate(std::vector& events ADD_CUSTOM_EVENT(events, tx); } + REWIND_BLOCKS_N(events, blk_0r, blk_0, miner, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + + // Construct a valid transaction and then modify it so that the transaction is no longer semantically correct. + + // No inputs. + { + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + tx.vin = {}; + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + } + + // Unsupported input type. + { + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + tx.vin.emplace_back(txin_gen{}); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + } + + // Unsupported output type. + { + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + tx.vout.emplace_back(); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + } + + // Inputs amount overflow. + { + point_t point_public_key{}; + txout_to_key target{}; + std::array inputs{}; + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + CHECK_AND_ASSERT_EQ(point_public_key.from_string("499790c3302b9f0514e2db09b390679283d43d971383d33dc24c7991ea4cf6d7"), true); + target.key = point_public_key.to_public_key(); + inputs.at(0).amount = 1; + inputs.at(1).amount = UINT64_MAX; + + for (const auto& input : inputs) + { + tx.vin.push_back(input); + } + + CHECK_AND_ASSERT_GREATER(inputs.at(0).amount, inputs.at(0).amount + inputs.at(1).amount); + CHECK_AND_ASSERT_GREATER(inputs.at(1).amount, inputs.at(0).amount + inputs.at(1).amount); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + } + + // Outputs amount overflow. + { + point_t point_public_key{}; + txout_to_key target{}; + std::array outputs{}; + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + CHECK_AND_ASSERT_EQ(point_public_key.from_string("78ef3d9af7b5e3d09556d57820cf68c2b3553a9d8205c01fe40fc70aae86bb4f"), true); + target.key = point_public_key.to_public_key(); + outputs.at(0).amount = 1; + outputs.at(1).amount = UINT64_MAX; + + for (auto& output : outputs) + { + output.target = target; + tx.vout.push_back(output); + } + + tx.vin.push_back(txin_to_key{}); + + CHECK_AND_ASSERT_GREATER(outputs.at(0).amount, outputs.at(0).amount + outputs.at(1).amount); + CHECK_AND_ASSERT_GREATER(outputs.at(1).amount, outputs.at(0).amount + outputs.at(1).amount); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + } + + // Equal key images in inputs. + { + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + + { + txin_zc_input input_zc{}; + txin_htlc input_htlc{}; + txin_to_key input_to_key{}; + point_t point_key_image{}; + + CHECK_AND_ASSERT_EQ(point_key_image.from_string("93fa59f43fb9cff98e6867d20cf200c98b29cae406acdbde798ffb3e30d3503a"), true); + input_zc.k_image = point_key_image.to_key_image(); + CHECK_AND_ASSERT_EQ(point_key_image.from_string("ad1226e3fd1be15e26b119fa80380e580a498e5fa3421b63fded89672b526a44"), true); + input_htlc.k_image = point_key_image.to_key_image(); + CHECK_AND_ASSERT_EQ(point_key_image.from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true); + input_to_key.k_image = point_key_image.to_key_image(); + tx.vin.push_back(input_zc); + tx.vin.push_back(input_htlc); + tx.vin.push_back(input_to_key); + } + + for (int8_t step{}; step < 3; ++step) + { + tx.vin.push_back(tx.vin.front()); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + tx.vin.erase(tx.vin.begin(), tx.vin.begin() + 1); + } + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + } + + // Two entries of the same type in extra. + { + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(2), TESTS_DEFAULT_FEE, blk_0r); + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + tx.extra.push_back(null_pkey); + tx.extra.push_back(null_pkey); + + CHECK_AND_ASSERT_GREATER(tx.extra.size(), 2); + CHECK_AND_ASSERT_EQ(typeid(tx.extra.back()), typeid(tx.extra.at(tx.extra.size() - 2))); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + } + + // tx.version <= TRANSACTION_VERSION_PRE_HF4. Balance check fail: sum of inputs <= sum of outputs. + { + tx_out_bare output{}; + std::array key_image_points{}; + std::array inputs{}; + MAKE_TX_FEE(events, tx, miner, miner, MK_TEST_COINS(1), TESTS_DEFAULT_FEE, blk_0r); + + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), true); + output.amount = 10'000'000'003; + tx.vout.push_back(output); + tx.version = 0; + CHECK_AND_ASSERT_EQ(key_image_points.at(0).from_string("8fc7cbfd1054690767d0c20917a68371b34b190aac5997581641f064b93d1b96"), true); + CHECK_AND_ASSERT_EQ(key_image_points.at(1).from_string("dc48b741dacda5ac026ad0a7d193b816049eb08724907a1ff6f95839cfb0efa5"), true); + + for (int position{}; position < 2; ++position) + { + auto& input{inputs.at(position)}; + + input.amount = 1; + input.k_image = key_image_points.at(position).to_key_image(); + tx.vin.push_back(input); + } + + const auto inputs_sum{[](const uint64_t sum, const txin_v& input) -> uint64_t + { + if (input.type() == typeid(txin_to_key)) + { + return sum + boost::get(input).amount; + } + + if (input.type() == typeid(txin_multisig)) + { + return sum + boost::get(input).amount; + } + + return sum; + } + }; + + const auto outputs_sum{[](const uint64_t sum, const tx_out_v& output) -> uint64_t + { + if (output.type() == typeid(tx_out_bare)) + { + return sum + boost::get(output).amount; + } + + return sum; + } + }; + + const uint64_t inputs_amount{std::accumulate(tx.vin.begin(), tx.vin.end(), std::uint64_t{}, inputs_sum)}; + const uint64_t outputs_amount{std::accumulate(tx.vout.begin(), tx.vout.end(), std::uint64_t{}, outputs_sum)}; + + CHECK_AND_ASSERT_LESS(inputs_amount, outputs_amount); + CHECK_AND_ASSERT_EQ(outputs_amount - inputs_amount, 1); + CHECK_AND_ASSERT(tx.version <= TRANSACTION_VERSION_PRE_HF4, false); + CHECK_AND_ASSERT_EQ(get_block_height(blk_0r), 10); + CHECK_AND_ASSERT_EQ(m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_03, 10), true); + CHECK_AND_ASSERT_EQ(m_hardforks.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 10), false); + CHECK_AND_ASSERT_EQ(validate_tx_semantic(tx, CURRENCY_MAX_TRANSACTION_BLOB_SIZE - 1), false); + DO_CALLBACK(events, "mark_invalid_tx"); + ADD_CUSTOM_EVENT(events, tx); + } + return true; } diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 5a8f81cd..9888ee3e 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -161,7 +161,7 @@ struct tx_version_against_hardfork : public test_chain_unit_enchanced bool generate(std::vector& events) const; }; -struct tx_pool_semantic_validation : public test_chain_unit_enchanced +struct tx_pool_semantic_validation : public test_chain_unit_enchanced { bool generate(std::vector& events) const; }; diff --git a/tests/core_tests/wallet_test_core_proxy.cpp b/tests/core_tests/wallet_test_core_proxy.cpp index db0fd0fc..b7da7b2e 100644 --- a/tests/core_tests/wallet_test_core_proxy.cpp +++ b/tests/core_tests/wallet_test_core_proxy.cpp @@ -89,7 +89,7 @@ bool wallet_test_core_proxy::call_COMMAND_RPC_GET_BLOCKS_FAST(const currency::CO rsp.current_height = m_blocks.size(); rsp.status = API_RETURN_CODE_OK; - if (!m_first_call) + if (!m_first_call && rsp.start_height != 0 /*second condition needed for re-sync in concise_mode*/) { m_first_call = true; return true; // respond with empty blocks on second call to gracefully stop wallet refreshing diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index cba1fadb..79eb631d 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1490,6 +1490,9 @@ bool gen_wallet_decrypted_attachments::generate(std::vector& e REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CREATE_TEST_WALLET(alice_wlt, alice_acc, blk_0); + //disable concise because this test count on on_transfer callbacks and resync cause firing on_transfer() for previous transactions + alice_wlt->set_concise_mode(false); + REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_0r, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); // these attachments will be used across all the transactions in this test @@ -3819,6 +3822,7 @@ bool wallet_and_sweep_below::c1(currency::core& c, size_t ev_index, const std::v //------------------------------------------------------------------------------ + block_template_blacklist_test::block_template_blacklist_test() { REGISTER_CALLBACK_METHOD(block_template_blacklist_test, c1); @@ -3908,3 +3912,64 @@ bool block_template_blacklist_test::c1(currency::core& c, size_t ev_index, const return true; } + +//------------------------------------------------------------------------------ + +wallet_reorganize_and_trim_test::wallet_reorganize_and_trim_test() +{ + REGISTER_CALLBACK_METHOD(wallet_reorganize_and_trim_test, c1); +} + +bool wallet_reorganize_and_trim_test::generate(std::vector& events) const +{ + uint64_t ts = test_core_time::get_time(); + m_accounts.resize(1); + account_base preminer_acc; + preminer_acc.generate(); + preminer_acc.set_createtime(ts); + account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts); + MAKE_GENESIS_BLOCK(events, blk_0, preminer_acc, ts); + DO_CALLBACK(events, "configure_core"); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, preminer_acc); + + REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW - 1); + + DO_CALLBACK(events, "c1"); + return true; + +} + +bool wallet_reorganize_and_trim_test::c1(currency::core& c, size_t ev_index, const std::vector& events) +{ + std::shared_ptr miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX); + //mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 2); +#define WALLET_REORGANIZE_AND_TRIM_TEST_REORG_SIZE 10 + miner_wlt->set_concise_mode(true); + miner_wlt->set_concise_mode_reorg_max_reorg_blocks(6); + + account_base acc; + acc.generate(); + std::shared_ptr alice = init_playtime_test_wallet(events, c, acc); + miner_wlt->refresh(); + miner_wlt->transfer(COIN, alice->get_account().get_public_address()); + mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 2); + + mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_REORGANIZE_AND_TRIM_TEST_REORG_SIZE); + uint64_t h1 = c.get_blockchain_storage().get_top_block_height(); + miner_wlt->refresh(); + uint64_t unlocked = 0; + uint64_t total = miner_wlt->balance(unlocked); + + c.get_blockchain_storage().truncate_blockchain(c.get_blockchain_storage().get_top_block_height() - (WALLET_REORGANIZE_AND_TRIM_TEST_REORG_SIZE-1)); + mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 10); + uint64_t h2 = c.get_blockchain_storage().get_top_block_height(); + miner_wlt->refresh(); + uint64_t unlocked2 = 0; + uint64_t total2 = miner_wlt->balance(unlocked2); + if (unlocked2 != unlocked || total2 != total) + { + CHECK_AND_ASSERT_MES(false, false, "wallet concise mode check failed"); + } + return true; +} diff --git a/tests/core_tests/wallet_tests.h b/tests/core_tests/wallet_tests.h index cad3871e..ab7a109c 100644 --- a/tests/core_tests/wallet_tests.h +++ b/tests/core_tests/wallet_tests.h @@ -301,4 +301,11 @@ struct block_template_blacklist_test : public wallet_test block_template_blacklist_test(); bool generate(std::vector& events) const; bool c1(currency::core& c, size_t ev_index, const std::vector& events); +}; + +struct wallet_reorganize_and_trim_test : public wallet_test +{ + wallet_reorganize_and_trim_test(); + bool generate(std::vector& events) const; + bool c1(currency::core& c, size_t ev_index, const std::vector& events); }; \ No newline at end of file diff --git a/tests/core_tests/wallet_tests_basic.h b/tests/core_tests/wallet_tests_basic.h index 885f8809..be112438 100644 --- a/tests/core_tests/wallet_tests_basic.h +++ b/tests/core_tests/wallet_tests_basic.h @@ -60,6 +60,8 @@ struct wallet_test : virtual public test_chain_unit_enchanced w->set_genesis(genesis_hash); w->set_core_proxy(m_core_proxy); w->set_disable_tor_relay(true); + w->set_concise_mode(true); + w->set_concise_mode_reorg_max_reorg_blocks(TESTS_CONCISE_MODE_REORG_MAX_REORG_BLOCK); return w; #undef LOCAL_HOST_CSTR diff --git a/tests/functional_tests/core_concurrency_test.cpp b/tests/functional_tests/core_concurrency_test.cpp index c0b70781..3fcbc00c 100644 --- a/tests/functional_tests/core_concurrency_test.cpp +++ b/tests/functional_tests/core_concurrency_test.cpp @@ -450,7 +450,7 @@ namespace boost bool core_concurrency_test(boost::program_options::variables_map& vm, size_t wthreads, size_t rthreads, size_t blocks_count) { log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); - //epee::debug::get_set_enable_assert(true, false); + epee::debug::get_set_enable_assert(true, false); log_space::get_set_need_thread_id(true, true); cct_accounts_t accounts(s_wallets_total_count); diff --git a/tests/functional_tests/crypto_tests.cpp b/tests/functional_tests/crypto_tests.cpp index 28a9b18c..599922f2 100644 --- a/tests/functional_tests/crypto_tests.cpp +++ b/tests/functional_tests/crypto_tests.cpp @@ -1966,9 +1966,9 @@ TEST(crypto, generators_precomp) #undef CHECK_PRECOMP } - -#include "bitcoin-secp256k1/include/secp256k1.h" -TEST(crypto, secp256k1_ecdsa_native) +#ifndef USE_OPEN_SSL_FOR_ECDSA + #include "bitcoin-secp256k1/include/secp256k1.h" + TEST(crypto, secp256k1_ecdsa_native) { bool r = false; @@ -2026,7 +2026,7 @@ TEST(crypto, secp256k1_ecdsa_native) secp256k1_context_destroy(ctx); return true; } - +#endif TEST(crypto, eth_signature_basics) { diff --git a/tests/functional_tests/crypto_tests_performance.h b/tests/functional_tests/crypto_tests_performance.h index b79a1bc6..fff2f461 100644 --- a/tests/functional_tests/crypto_tests_performance.h +++ b/tests/functional_tests/crypto_tests_performance.h @@ -1340,7 +1340,6 @@ TEST(perf, point_eq_vs_iszero) return true; } - TEST(perf, buff_to_hex) { std::vector in_buffs; diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 95646b63..07707a2d 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -197,9 +197,9 @@ uint64_t got_money_in_first_transfers(const tools::transfer_container& incoming_ { uint64_t summ = 0; size_t count = 0; - BOOST_FOREACH(const tools::transfer_details& td, incoming_transfers) + for(auto& tr : incoming_transfers) { - summ += boost::get(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index]).amount; + summ += boost::get(tr.second.m_ptx_wallet_info->m_tx.vout[tr.second.m_internal_output_index]).amount; if(++count >= n_transfers) return summ; } @@ -245,9 +245,9 @@ std::string get_incoming_transfers_str(tools::wallet2& w) uint64_t spent_count = 0; uint64_t unspent_count = 0; - for (const auto& td : transfers) + for (const auto& tr : transfers) { - if (td.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT) + if (tr.second.m_flags&WALLET_TRANSFER_DETAIL_FLAG_SPENT) { ++spent_count; } @@ -469,8 +469,9 @@ bool transactions_flow_test( //lets go! size_t count = 0; prepared_transfers = 0; - BOOST_FOREACH(tools::transfer_details& td, incoming_transfers) + for(const auto& tr : incoming_transfers) { + const tools::transfer_details& td = tr.second; if (td.is_spent()) continue; diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 1055bfca..9b285b68 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -24,9 +24,10 @@ #include "free_space_check.h" #include "htlc_hash_tests.h" #include "threads_pool_tests.h" -#include "wallet/plain_wallet_api.h" +#include "wallet/plain_wallet_api.h" #include "wallet/view_iface.h" - +#include "wallet/plain_wallet_api_defs.h" + PUSH_VS_WARNINGS DISABLE_VS_WARNINGS(4244) #include "jwt-cpp/jwt.h" @@ -34,9 +35,15 @@ POP_VS_WARNINGS void test_plain_wallet() { - std::string res = plain_wallet::init("195.201.107.230", "33340", "C:\\Users\\roky\\home\\", 0); + //std::string res = plain_wallet::init("195.201.107.230", "33340", "C:\\Users\\roky\\home\\", 0); + std::string res = plain_wallet::init("", "", "C:\\Users\\roky\\home\\", 0); //std::string res = plain_wallet::init("127.0.0.1", "12111", "C:\\Users\\roky\\home22\\", 0); + plain_wallet::configure_object conf = AUTO_VAL_INIT(conf); + //plain_wallet::configure_response conf_resp = AUTO_VAL_INIT(conf_resp); + conf.postponed_run_wallet = true; + std::string r = plain_wallet::sync_call("configure", 0, epee::serialization::store_t_to_json(conf)); + std::string res___ = plain_wallet::get_wallet_files(); @@ -46,6 +53,10 @@ void test_plain_wallet() //res = plain_wallet::restore("", // "test_restored_2.zan", "111", ""); + epee::misc_utils::sleep_no_w(2000); + + res = plain_wallet::sync_call("reset_connection_url", 0, "195.201.107.230:33336"); + r = plain_wallet::sync_call("run_wallet", instance_id, ""); while(true) { @@ -53,6 +64,7 @@ void test_plain_wallet() res = plain_wallet::sync_call("get_wallet_status", instance_id, ""); view::wallet_sync_status_info wsi = AUTO_VAL_INIT(wsi); epee::serialization::load_t_from_json(wsi, res); + LOG_PRINT_L0("Progress: " << wsi.progress); if (wsi.wallet_state == 2) break; } diff --git a/tests/unit_tests/multiassets_test.cpp b/tests/unit_tests/multiassets_test.cpp index a996acad..ad637b01 100644 --- a/tests/unit_tests/multiassets_test.cpp +++ b/tests/unit_tests/multiassets_test.cpp @@ -4,7 +4,6 @@ #include -#include #include #include @@ -20,1295 +19,916 @@ namespace currency { - struct asset_descriptor_base_v0; - struct asset_descriptor_operation_v0; -} -// develop, commit 0c90262e8a1c4e5e5d052f8db84c60a36691414d -struct currency::asset_descriptor_base_v0 -{ - uint64_t total_max_supply = 0; - uint64_t current_supply = 0; - uint8_t decimal_point = 0; - std::string ticker; - std::string full_name; - std::string meta_info; - crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8 - bool hidden_supply = false; - uint8_t version = 0; - - BEGIN_VERSIONED_SERIALIZE(0, version) - FIELD(total_max_supply) - FIELD(current_supply) - FIELD(decimal_point) - FIELD(ticker) - FIELD(full_name) - FIELD(meta_info) - FIELD(owner) - FIELD(hidden_supply) - END_SERIALIZE() - - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(total_max_supply) - BOOST_SERIALIZE(current_supply) - BOOST_SERIALIZE(decimal_point) - BOOST_SERIALIZE(ticker) - BOOST_SERIALIZE(full_name) - BOOST_SERIALIZE(meta_info) - BOOST_SERIALIZE(owner) - BOOST_SERIALIZE(hidden_supply) - END_BOOST_SERIALIZATION() - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for given asset, can't be changed after deployment") DOC_EXMP(1000000000000000000) DOC_END - KV_SERIALIZE(current_supply) DOC_DSCR("Currently emitted supply for given asset (ignored for REGISTER operation)") DOC_EXMP(500000000000000000) DOC_END - KV_SERIALIZE(decimal_point) DOC_DSCR("Decimal point") DOC_EXMP(12) DOC_END - KV_SERIALIZE(ticker) DOC_DSCR("Ticker associated with asset") DOC_EXMP("ZUSD") DOC_END - KV_SERIALIZE(full_name) DOC_DSCR("Full name of the asset") DOC_EXMP("Zano wrapped USD") DOC_END - KV_SERIALIZE(meta_info) DOC_DSCR("Any other information assetiaded with asset in a free form") DOC_EXMP("Stable and private") DOC_END - KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used only for EMIT and UPDATE validation, could be changed by transferring asset ownership") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END - KV_SERIALIZE(hidden_supply) DOC_DSCR("This one reserved for future use, will be documented later") DOC_END - END_KV_SERIALIZE_MAP() - - operator currency::asset_descriptor_base() const + // + // The following structures are taken as-id from branch develop, commit 0c90262e8a1c4e5e5d052f8db84c60a36691414d, for backward compatibility serialization test. + // DO NOT EDIT THEM without a very good reason + // + struct asset_descriptor_base_v0 // EDITED: was asset_descriptor_base originally, changed to asset_descriptor_base_v0 { - currency::asset_descriptor_base asset_descriptor{}; - asset_descriptor.total_max_supply = total_max_supply; - asset_descriptor.current_supply = current_supply; - asset_descriptor.decimal_point = decimal_point; - asset_descriptor.ticker = ticker; - asset_descriptor.full_name = full_name; - asset_descriptor.meta_info = meta_info; - asset_descriptor.owner = owner; - asset_descriptor.hidden_supply = hidden_supply; - asset_descriptor.version = version; - return asset_descriptor; - } -}; + uint64_t total_max_supply = 0; + uint64_t current_supply = 0; + uint8_t decimal_point = 0; + std::string ticker; + std::string full_name; + std::string meta_info; + crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8 + bool hidden_supply = false; + uint8_t version = 0; -struct currency::asset_descriptor_operation_v0 -{ - uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; - asset_descriptor_base_v0 descriptor; - crypto::public_key amount_commitment; // premultiplied by 1/8 - boost::optional opt_asset_id; // target asset_id - for update/emit - uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER; + BEGIN_VERSIONED_SERIALIZE(0, version) + FIELD(total_max_supply) + FIELD(current_supply) + FIELD(decimal_point) + FIELD(ticker) + FIELD(full_name) + FIELD(meta_info) + FIELD(owner) + FIELD(hidden_supply) + END_SERIALIZE() - BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER, verion) - FIELD(operation_type) - FIELD(descriptor) - FIELD(amount_commitment) - END_VERSION_UNDER(1) - FIELD(opt_asset_id) - END_SERIALIZE() - BEGIN_BOOST_SERIALIZATION() - BOOST_SERIALIZE(operation_type) - BOOST_SERIALIZE(descriptor) - BOOST_SERIALIZE(amount_commitment) - BOOST_END_VERSION_UNDER(1) - BOOST_SERIALIZE(opt_asset_id) - END_BOOST_SERIALIZATION() + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(total_max_supply) + BOOST_SERIALIZE(current_supply) + BOOST_SERIALIZE(decimal_point) + BOOST_SERIALIZE(ticker) + BOOST_SERIALIZE(full_name) + BOOST_SERIALIZE(meta_info) + BOOST_SERIALIZE(owner) + BOOST_SERIALIZE(hidden_supply) + END_BOOST_SERIALIZATION() - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(operation_type) DOC_DSCR("Asset operation type identifier") DOC_EXMP(1) DOC_END - KV_SERIALIZE(descriptor) DOC_DSCR("Asset descriptor") DOC_EXMP_AUTO() DOC_END - KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitment) DOC_DSCR("Amount commitment") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END - KV_SERIALIZE_POD_AS_HEX_STRING(opt_asset_id) DOC_DSCR("ID of an asset.") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END - END_KV_SERIALIZE_MAP() + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for given asset, can't be changed after deployment") DOC_EXMP(1000000000000000000) DOC_END + KV_SERIALIZE(current_supply) DOC_DSCR("Currently emitted supply for given asset (ignored for REGISTER operation)") DOC_EXMP(500000000000000000) DOC_END + KV_SERIALIZE(decimal_point) DOC_DSCR("Decimal point") DOC_EXMP(12) DOC_END + KV_SERIALIZE(ticker) DOC_DSCR("Ticker associated with asset") DOC_EXMP("ZUSD") DOC_END + KV_SERIALIZE(full_name) DOC_DSCR("Full name of the asset") DOC_EXMP("Zano wrapped USD") DOC_END + KV_SERIALIZE(meta_info) DOC_DSCR("Any other information assetiaded with asset in a free form") DOC_EXMP("Stable and private") DOC_END + KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used only for EMIT and UPDATE validation, could be changed by transferring asset ownership") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END + KV_SERIALIZE(hidden_supply) DOC_DSCR("This one reserved for future use, will be documented later") DOC_END + END_KV_SERIALIZE_MAP() + }; - operator currency::asset_descriptor_operation() const + #define ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER_V0 1 + + struct asset_descriptor_operation_v0 // EDITED: was asset_descriptor_operation originally, changed to asset_descriptor_operation_v0 { - currency::asset_descriptor_operation operation_descriptor{}; - operation_descriptor.operation_type = operation_type; - operation_descriptor.descriptor = descriptor; - operation_descriptor.amount_commitment = amount_commitment; - operation_descriptor.opt_asset_id = opt_asset_id; - operation_descriptor.verion = verion; + uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; + asset_descriptor_base_v0 descriptor; // EDITED: was asset_descriptor_base originally, changed to asset_descriptor_base_v0 + crypto::public_key amount_commitment; // premultiplied by 1/8 + boost::optional opt_asset_id; // target asset_id - for update/emit + uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER_V0; // EDITED: was ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER originally, changed to ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER_V0 - return operation_descriptor; - } -}; + BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER_V0, verion) // EDITED: was ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER originally, changed to ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER_V0 + FIELD(operation_type) + FIELD(descriptor) + FIELD(amount_commitment) + END_VERSION_UNDER(1) + FIELD(opt_asset_id) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(operation_type) + BOOST_SERIALIZE(descriptor) + BOOST_SERIALIZE(amount_commitment) + BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(opt_asset_id) + END_BOOST_SERIALIZATION() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(operation_type) DOC_DSCR("Asset operation type identifier") DOC_EXMP(1) DOC_END + KV_SERIALIZE(descriptor) DOC_DSCR("Asset descriptor") DOC_EXMP_AUTO() DOC_END + KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitment) DOC_DSCR("Amount commitment") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END + KV_SERIALIZE_POD_AS_HEX_STRING(opt_asset_id) DOC_DSCR("ID of an asset.") DOC_EXMP("cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6") DOC_END + END_KV_SERIALIZE_MAP() + }; + + // + // End: Code insertion from commit 0c90262e8a1c4e5e5d052f8db84c60a36691414d + // + +} // namespace currency BOOST_CLASS_VERSION(currency::asset_descriptor_operation_v0, 1); +BOOST_CLASS_VERSION(currency::asset_descriptor_base_v0, 0); -currency::asset_descriptor_base get_asset_descriptor_for_test( - const crypto::public_key& owner = currency::null_pkey) + +template +static asset_descriptor get_adb(const crypto::public_key& owner = currency::null_pkey) { - currency::asset_descriptor_base descriptor_base{}; - descriptor_base.total_max_supply = 100; - descriptor_base.current_supply = 50; - descriptor_base.decimal_point = 0; - descriptor_base.ticker = "HLO"; - descriptor_base.full_name = "HELLO_WORLD"; - descriptor_base.meta_info = "Hello, world!"; - descriptor_base.owner = owner; - descriptor_base.hidden_supply = false; - descriptor_base.version = 1; + if (const auto& id{typeid(asset_descriptor)}; id != typeid(currency::asset_descriptor_base) && id != typeid(currency::asset_descriptor_base_v0)) + { + throw "Unsupported type of an asset descriptor"; + } - return descriptor_base; + asset_descriptor descriptor{}; + + descriptor.total_max_supply = 100; + descriptor.current_supply = 50; + descriptor.decimal_point = 0; + descriptor.ticker = "HLO"; + descriptor.full_name = "HELLO_WORLD"; + descriptor.meta_info = "Hello, world!"; + descriptor.owner = owner; + descriptor.hidden_supply = false; + + if (typeid(asset_descriptor) == typeid(currency::asset_descriptor_base)) + { + descriptor.version = 1; + } + + return descriptor; } -currency::asset_descriptor_base_v0 get_asset_descriptor_v0_for_test( - const crypto::public_key& owner = currency::null_pkey) +template +static asset_operation_descriptor get_ado(const asset_base_descriptor& base_descriptor, std::uint8_t operation = ASSET_DESCRIPTOR_OPERATION_UNDEFINED, + std::optional asset_id = currency::null_pkey) { - currency::asset_descriptor_base_v0 descriptor_base{}; - descriptor_base.total_max_supply = 100; - descriptor_base.current_supply = 50; - descriptor_base.decimal_point = 0; - descriptor_base.ticker = "HLO"; - descriptor_base.full_name = "HELLO_WORLD"; - descriptor_base.meta_info = "Hello, world!"; - descriptor_base.owner = owner; - descriptor_base.hidden_supply = false; + if (const auto& id{typeid(asset_operation_descriptor)}; id != typeid(currency::asset_descriptor_operation) && id != typeid(currency::asset_descriptor_operation_v0)) + { + throw "Unsupported type of an asset operation descriptor"; + } - return descriptor_base; + if (const auto& id{typeid(asset_base_descriptor)}; id != typeid(currency::asset_descriptor_base) && id != typeid(currency::asset_descriptor_base_v0)) + { + throw "Unsupported type of an asset base descriptor"; + } + + asset_operation_descriptor descriptor{}; + descriptor.operation_type = operation; + descriptor.opt_descriptor = base_descriptor; + descriptor.opt_amount_commitment = currency::null_pkey; + + if (asset_id.has_value()) + { + descriptor.opt_asset_id = asset_id.value(); + } + + return descriptor; } -currency::asset_descriptor_operation get_asset_descriptor_operation_for_test( - currency::asset_descriptor_base asset_descriptor, - std::uint8_t operation = ASSET_DESCRIPTOR_OPERATION_UNDEFINED -) +enum class serialization_method : uint8_t { - currency::asset_descriptor_operation descriptor_operation{}; - descriptor_operation.operation_type = operation; - descriptor_operation.descriptor = asset_descriptor; - descriptor_operation.amount_commitment = currency::null_pkey; + native, + boost, + key_value +}; - return descriptor_operation; +template +static std::optional serialize(serialization_method method, const asset_operation_descriptor& descriptor) +{ + if (const auto& id{typeid(asset_operation_descriptor)}; id != typeid(currency::asset_descriptor_operation) && id != typeid(currency::asset_descriptor_operation_v0)) + { + throw "Unsupported type of an asset descriptor operation"; + } + + std::function serialization_function{}; + + switch (method) + { + case serialization_method::native: + serialization_function = static_cast(t_serializable_object_to_blob); + break; + + case serialization_method::boost: + serialization_function = static_cast(tools::serialize_obj_to_buff); + break; + + case serialization_method::key_value: + serialization_function = [](const asset_operation_descriptor& descriptor, std::string& presentation) -> bool + { + return epee::serialization::store_t_to_json(descriptor, presentation); + }; + break; + } + + if (std::string presentation{}; serialization_function.operator bool() && serialization_function(descriptor, presentation)) + { + return presentation; + } + + return {}; } -currency::asset_descriptor_operation_v0 -get_asset_descriptor_operation_v0_for_test( - currency::asset_descriptor_base_v0 asset_descriptor, - std::uint8_t operation = ASSET_DESCRIPTOR_OPERATION_UNDEFINED -) +template +static std::optional deserialize(serialization_method method, const std::string& presentation) { - currency::asset_descriptor_operation_v0 descriptor_operation{}; - descriptor_operation.operation_type = operation; - descriptor_operation.descriptor = asset_descriptor; - descriptor_operation.amount_commitment = currency::null_pkey; + if (const auto& id{typeid(asset_operation_descriptor)}; id != typeid(currency::asset_descriptor_operation) && id != typeid(currency::asset_descriptor_operation_v0)) + { + throw "Unsupported type of an asset descriptor operation"; + } - return descriptor_operation; + std::function deserialization_function{}; + + switch (method) + { + case serialization_method::native: + deserialization_function = t_unserializable_object_from_blob; + break; + + case serialization_method::boost: + deserialization_function = tools::unserialize_obj_from_buff; + break; + + case serialization_method::key_value: + deserialization_function = epee::serialization::load_t_from_json; + break; + } + + if (asset_operation_descriptor descriptor{}; deserialization_function.operator bool() && deserialization_function(descriptor, presentation)) + { + return descriptor; + } + + return {}; } -TEST(multiassets, get_or_calculate_asset_id_register) +static std::string get_string_presentation(const std::string& data) { - bool success{false}; + std::string presentation{}; - crypto::point_t pt_public_key{}; - success = pt_public_key.from_string( - "cf93bead4d2a8d6d174c1752237b2e5208a594b59618683ee50ef209cf1efb19"); + for (int position{}; position < data.size(); ++position) + { + const auto character{static_cast(data.at(position))}; - ASSERT_TRUE(success); + if (std::isprint(character)) + { + presentation += '\''; - crypto::public_key owner_public_key{}; - pt_public_key.to_public_key(owner_public_key); + if (character == '\'') + { + presentation += '\\'; + } - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; + presentation += character; + presentation += '\''; + } - const auto asset_descriptor{get_asset_descriptor_for_test(owner_public_key)}; + else + { + std::stringstream stream{}; - const auto asset_operation_descriptor{ - get_asset_descriptor_operation_for_test(asset_descriptor, - ASSET_DESCRIPTOR_OPERATION_REGISTER)}; + presentation += "\'\\x"; + stream << std::hex << std::setw(2) << std::setfill('0') << static_cast(character); + presentation += stream.str(); + presentation += '\''; + } - success = currency::get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); + if (position < data.size() - 1) + { + presentation += ", "; + } + } - ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); -} - -TEST(multiassets, get_or_calculate_asset_id_emit) -{ - bool success{false}; - - crypto::point_t pt_public_key{}; - success = pt_public_key.from_string( - "edab571c4be9eabfea5e7883036d744c097382eb6f739a914db06f72ba35099d"); - - ASSERT_TRUE(success); - - crypto::public_key owner_public_key{}; - pt_public_key.to_public_key(owner_public_key); - - const auto asset_descriptor{ - get_asset_descriptor_for_test(owner_public_key)}; - - auto asset_operation_descriptor{ - get_asset_descriptor_operation_for_test( - asset_descriptor, ASSET_DESCRIPTOR_OPERATION_REGISTER)}; - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - - ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); - - asset_operation_descriptor.opt_asset_id = calculated_asset_id_key; - asset_operation_descriptor.operation_type = ASSET_DESCRIPTOR_OPERATION_EMIT; - - success = get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - - ASSERT_TRUE(success); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); -} - -TEST(multiassets, get_or_calculate_asset_id_update) -{ - bool success{false}; - - crypto::point_t pt_public_key{}; - success = pt_public_key.from_string( - "8cb6349f51da6599feeae7c0077293436eb6a5000f0e6e706e77886bb540e2c1"); - - ASSERT_TRUE(success); - - crypto::public_key owner_public_key{}; - pt_public_key.to_public_key(owner_public_key); - - const auto asset_descriptor{ - get_asset_descriptor_for_test(owner_public_key)}; - - auto asset_operation_descriptor{ - get_asset_descriptor_operation_for_test( - asset_descriptor, ASSET_DESCRIPTOR_OPERATION_REGISTER)}; - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - - ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); - - asset_operation_descriptor.opt_asset_id = calculated_asset_id_key; - asset_operation_descriptor.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE; - - success = get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - - ASSERT_TRUE(success); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); -} - -TEST(multiassets, get_or_calculate_asset_id_public_burn) -{ - bool success{false}; - - crypto::point_t pt_public_key{}; - success = pt_public_key.from_string( - "0c408cf8b7fb808f40593d6eb75890e2ab3d0ccdc7014a7fc6b6ab05163be060"); - - ASSERT_TRUE(success); - - crypto::public_key owner_public_key{}; - pt_public_key.to_public_key(owner_public_key); - - const auto asset_descriptor{ - get_asset_descriptor_for_test(owner_public_key)}; - - auto asset_operation_descriptor{ - get_asset_descriptor_operation_for_test( - asset_descriptor, ASSET_DESCRIPTOR_OPERATION_REGISTER)}; - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - - ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "54f3f72c72e5b014ad2b2b9001acef954fe82dd3ed56a38cd9ddc5db57673f8f"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); - - asset_operation_descriptor.opt_asset_id = calculated_asset_id_key; - asset_operation_descriptor.operation_type = - ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN; - - success = get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - - ASSERT_TRUE(success); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + return presentation; } TEST(multiassets, get_or_calculate_asset_id_undefined) { - bool success{false}; - - crypto::point_t pt_public_key{}; - success = pt_public_key.from_string( - "e91b9a73292d6ea46fb3d4f4cc79c34bfb7d14c2e684e58093a2471c92e51c16"); + bool success{}; + crypto::point_t point_owner{}; + crypto::public_key owner{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + currency::asset_descriptor_base adb{}; + currency::asset_descriptor_operation ado{}; + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + success = point_owner.from_string("e91b9a73292d6ea46fb3d4f4cc79c34bfb7d14c2e684e58093a2471c92e51c16"); ASSERT_TRUE(success); - - crypto::public_key owner_public_key{}; - pt_public_key.to_public_key(owner_public_key); - - const auto asset_descriptor{ - get_asset_descriptor_for_test(owner_public_key)}; - - auto asset_operation_descriptor{ - get_asset_descriptor_operation_for_test( - asset_descriptor, ASSET_DESCRIPTOR_OPERATION_REGISTER)}; - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - + owner = point_owner.to_public_key(); + adb = get_adb(owner); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "979eb706ace2eb83f9125658b23fb352208480cb3b90c43e2df0d298f9754ebc"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); + success = expected_point_asset_id.from_string("979eb706ace2eb83f9125658b23fb352208480cb3b90c43e2df0d298f9754ebc"); ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); - - asset_operation_descriptor.opt_asset_id = calculated_asset_id_key; - asset_operation_descriptor.operation_type = - ASSET_DESCRIPTOR_OPERATION_UNDEFINED; - - success = get_or_calculate_asset_id(asset_operation_descriptor, - &calculated_asset_id_pt, - &calculated_asset_id_key); - + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_asset_id); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_UNDEFINED, calculated_asset_id); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); ASSERT_FALSE(success); } -TEST(multiassets, get_or_calculate_asset_id_register_serialization) +TEST(multiassets, get_or_calculate_asset_id_register) { - bool success{false}; - currency::asset_descriptor_operation asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x01', '\x01', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x03', 'H', 'L', 'O', '\x0b', 'H', 'E', - 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', - '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', - 'o', 'r', 'l', 'd', '!', '\xcf', '\x93', '\xbe', '\xad', - 'M', '*', '\x8d', 'm', '\x17', 'L', '\x17', 'R', '#', - '{', '.', 'R', '\x08', '\xa5', '\x94', '\xb5', '\x96', '\x18', - 'h', '>', '\xe5', '\x0e', '\xf2', '\x09', '\xcf', '\x1e', '\xfb', - '\x19', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'o', - 'F', '2', 'O', '\xaa', '\xe4', 'H', '\xb9', '\xe3', '\xb9', - 'm', '\xac', '\x94', '\xda', '\x17', '\xbe', 'j', '\xb7', '\xea', - '\xab', '\xa3', '\x98', '\xde', '\x86', '\xd8', 't', '0', 'B', - '\xc9', '\x8b', '\xac', '\xe0'}; + bool success{}; + crypto::point_t point_owner{}; + crypto::public_key owner{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + currency::asset_descriptor_base adb{}; + currency::asset_descriptor_operation ado{}; + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; - success = t_unserializable_object_from_blob(asset_descriptor_operation, - serialized_asset_descriptor_operation); + success = point_owner.from_string("cf93bead4d2a8d6d174c1752237b2e5208a594b59618683ee50ef209cf1efb19"); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + point_owner.to_public_key(owner); + adb = get_adb(owner); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); + success = expected_point_asset_id.from_string("6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"); ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_emit_serialization) +TEST(multiassets, get_or_calculate_asset_id_emit) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x01', '\x02', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x03', 'H', 'L', 'O', '\x0b', 'H', 'E', - 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', - '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', - 'o', 'r', 'l', 'd', '!', '\xed', '\xab', 'W', '\x1c', - 'K', '\xe9', '\xea', '\xbf', '\xea', '^', 'x', '\x83', '\x03', - 'm', 't', 'L', '\x09', 's', '\x82', '\xeb', 'o', 's', - '\x9a', '\x91', 'M', '\xb0', 'o', 'r', '\xba', '5', '\x09', - '\x9d', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'I', - '\xa3', '\xd6', 'e', '*', '\xaa', '\x0b', ';', 'w', ')', - ',', 'S', 'N', '\x91', '\xff', '\x80', '\xde', '\x91', ' ', - '\xae', '\xb6', '\xfc', '\x1c', '^', '\xdc', 'r', '\x80', 'G', - 'C', '}', 'f', '~'}; + bool success{}; + crypto::point_t point_owner{}; + crypto::public_key owner{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + currency::asset_descriptor_base adb{}; + currency::asset_descriptor_operation ado{}; + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; - success = t_unserializable_object_from_blob(asset_descriptor_operation, - serialized_asset_descriptor_operation); + success = point_owner.from_string("edab571c4be9eabfea5e7883036d744c097382eb6f739a914db06f72ba35099d"); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + owner = point_owner.to_public_key(); + adb = get_adb(owner); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); + success = expected_point_asset_id.from_string("49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"); ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_asset_id); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_EMIT, calculated_asset_id); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_update_serialization) +TEST(multiassets, get_or_calculate_asset_id_update) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x01', '\x03', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x03', 'H', 'L', 'O', '\x0b', 'H', 'E', - 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', - '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', - 'o', 'r', 'l', 'd', '!', '\x8c', '\xb6', '4', '\x9f', - 'Q', '\xda', 'e', '\x99', '\xfe', '\xea', '\xe7', '\xc0', '\x07', - 'r', '\x93', 'C', 'n', '\xb6', '\xa5', '\x00', '\x0f', '\x0e', - 'n', 'p', 'n', 'w', '\x88', 'k', '\xb5', '@', '\xe2', - '\xc1', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xc3', - 'q', '\xf6', '\x0d', '\xd8', '3', '2', '\x98', '\xc6', '\xaa', - 't', 'k', 'q', '\xe1', '\xe2', '\x05', '\'', '\xb1', '\xff', - '^', '\x1b', '\xed', 'N', '\xa9', '\xb5', '\xf5', '\x92', '\xfa', - '\xdf', '\x90', '\xed', 'k'}; + bool success{}; + crypto::point_t point_owner{}; + crypto::public_key owner{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + currency::asset_descriptor_base adb{}; + currency::asset_descriptor_operation ado{}; + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; - success = t_unserializable_object_from_blob(asset_descriptor_operation, - serialized_asset_descriptor_operation); + success = point_owner.from_string("8cb6349f51da6599feeae7c0077293436eb6a5000f0e6e706e77886bb540e2c1"); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + owner = point_owner.to_public_key(); + adb = get_adb(owner); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); + success = expected_point_asset_id.from_string("c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"); ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_asset_id); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_UPDATE, calculated_asset_id); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_public_burn_serialization) +TEST(multiassets, get_or_calculate_asset_id_public_burn) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x01', '\x04', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x03', 'H', 'L', 'O', '\x0b', 'H', 'E', - 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', - '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', - 'o', 'r', 'l', 'd', '!', '\x0c', '@', '\x8c', '\xf8', - '\xb7', '\xfb', '\x80', '\x8f', '@', 'Y', '=', 'n', '\xb7', - 'X', '\x90', '\xe2', '\xab', '=', '\x0c', '\xcd', '\xc7', '\x01', - 'J', '\x7f', '\xc6', '\xb6', '\xab', '\x05', '\x16', ';', '\xe0', - '`', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'T', - '\xf3', '\xf7', ',', 'r', '\xe5', '\xb0', '\x14', '\xad', '+', - '+', '\x90', '\x01', '\xac', '\xef', '\x95', 'O', '\xe8', '-', - '\xd3', '\xed', 'V', '\xa3', '\x8c', '\xd9', '\xdd', '\xc5', '\xdb', - 'W', 'g', '?', '\x8f'}; + bool success{}; + crypto::point_t point_owner{}; + crypto::public_key owner{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + currency::asset_descriptor_base adb{}; + currency::asset_descriptor_operation ado{}; + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; - success = t_unserializable_object_from_blob(asset_descriptor_operation, - serialized_asset_descriptor_operation); + success = point_owner.from_string("0c408cf8b7fb808f40593d6eb75890e2ab3d0ccdc7014a7fc6b6ab05163be060"); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + owner = point_owner.to_public_key(); + adb = get_adb(owner); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "54f3f72c72e5b014ad2b2b9001acef954fe82dd3ed56a38cd9ddc5db57673f8f"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); + success = expected_point_asset_id.from_string("54f3f72c72e5b014ad2b2b9001acef954fe82dd3ed56a38cd9ddc5db57673f8f"); ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_asset_id); + ado = get_ado(adb, ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN, calculated_asset_id); + success = currency::get_or_calculate_asset_id(ado, &calculated_point_asset_id, &calculated_asset_id); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_undefined_serialization) +TEST(multiassets, native_serialization_get_or_calculate_asset_id_undefined) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x01', '\x00', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x03', 'H', 'L', 'O', '\x0b', 'H', 'E', - 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', - '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', - 'o', 'r', 'l', 'd', '!', '\xe9', '\x1b', '\x9a', 's', - ')', '-', 'n', '\xa4', 'o', '\xb3', '\xd4', '\xf4', '\xcc', - 'y', '\xc3', 'K', '\xfb', '}', '\x14', '\xc2', '\xe6', '\x84', - '\xe5', '\x80', '\x93', '\xa2', 'G', '\x1c', '\x92', '\xe5', '\x1c', - '\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x97', - '\x9e', '\xb7', '\x06', '\xac', '\xe2', '\xeb', '\x83', '\xf9', '\x12', - 'V', 'X', '\xb2', '?', '\xb3', 'R', ' ', '\x84', '\x80', - '\xcb', ';', '\x90', '\xc4', '>', '-', '\xf0', '\xd2', '\x98', - '\xf9', 'u', 'N', '\xbc'}; + bool success{}; + const std::string serialized_ado{'\x01', '\x00', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', + 'H', 'L', 'O', '\x0b', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\xe9', '\x1b', '\x9a', 's', ')', '-', 'n', + '\xa4', 'o', '\xb3', '\xd4', '\xf4', '\xcc', 'y', '\xc3', 'K', '\xfb', '}', '\x14', '\xc2', '\xe6', '\x84', '\xe5', '\x80', '\x93', '\xa2', 'G', '\x1c', '\x92', '\xe5', '\x1c', '\x16', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x97', '\x9e', '\xb7', '\x06', '\xac', '\xe2', '\xeb', '\x83', '\xf9', '\x12', 'V', 'X', '\xb2', '?', '\xb3', 'R', ' ', + '\x84', '\x80', '\xcb', ';', '\x90', '\xc4', '>', '-', '\xf0', '\xd2', '\x98', '\xf9', 'u', 'N', '\xbc'}; - success = t_unserializable_object_from_blob( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::native, serialized_ado)}; + + ASSERT_TRUE(ado.has_value() && ado->opt_descriptor.has_value()); + ASSERT_EQ(ado->version, 1); + ASSERT_EQ(ado->opt_descriptor->version, 0); + ASSERT_EQ(ado->operation_type, ASSET_DESCRIPTOR_OPERATION_UNDEFINED); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); + ASSERT_FALSE(success); + + std::string reserialized_ado = t_serializable_object_to_blob(ado.value()); + ASSERT_EQ(serialized_ado, reserialized_ado); +} + +TEST(multiassets, native_serialization_get_or_calculate_asset_id_register) +{ + bool success{}; + const std::string serialized_ado{'\x01', '\x01', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', + 'H', 'L', 'O', '\x0b', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\xcf', '\x93', '\xbe', '\xad', 'M', '*', + '\x8d', 'm', '\x17', 'L', '\x17', 'R', '#', '{', '.', 'R', '\x08', '\xa5', '\x94', '\xb5', '\x96', '\x18', 'h', '>', '\xe5', '\x0e', '\xf2', '\x09', '\xcf', '\x1e', '\xfb', '\x19', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; + + crypto::point_t expected_point_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::native, serialized_ado)}; + + ASSERT_TRUE(ado.has_value() && ado->opt_descriptor.has_value()); + ASSERT_EQ(ado->version, 1); + ASSERT_EQ(ado->opt_descriptor->version, 0); + ASSERT_EQ(ado->operation_type, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); + success = expected_point_asset_id.from_string("6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_point_asset_id.to_public_key()); - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; + std::string reserialized_ado = t_serializable_object_to_blob(ado.value()); + ASSERT_EQ(serialized_ado, reserialized_ado); +} - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); +TEST(multiassets, native_serialization_get_or_calculate_asset_id_emit) +{ + bool success{}; + const std::string serialized_ado{'\x01', '\x02', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', + 'H', 'L', 'O', '\x0b', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\xed', '\xab', 'W', '\x1c', 'K', '\xe9', + '\xea', '\xbf', '\xea', '^', 'x', '\x83', '\x03', 'm', 't', 'L', '\x09', 's', '\x82', '\xeb', 'o', 's', '\x9a', '\x91', 'M', '\xb0', 'o', 'r', '\xba', '5', '\x09', '\x9d', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'I', '\xa3', '\xd6', 'e', '*', '\xaa', '\x0b', ';', 'w', ')', ',', 'S', 'N', '\x91', '\xff', '\x80', '\xde', '\x91', ' ', '\xae', '\xb6', + '\xfc', '\x1c', '^', '\xdc', 'r', '\x80', 'G', 'C', '}', 'f', '~'}; + + crypto::point_t expected_point_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::native, serialized_ado)}; + + ASSERT_TRUE(ado.has_value() && ado->opt_descriptor.has_value()); + ASSERT_EQ(ado->version, 1); + ASSERT_EQ(ado->opt_descriptor->version, 0); + ASSERT_EQ(ado->operation_type, ASSET_DESCRIPTOR_OPERATION_EMIT); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); + ASSERT_TRUE(success); + success = expected_point_asset_id.from_string("49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_point_asset_id.to_public_key()); + + std::string reserialized_ado = t_serializable_object_to_blob(ado.value()); + ASSERT_EQ(serialized_ado, reserialized_ado); +} + +TEST(multiassets, native_serialization_get_or_calculate_asset_id_update) +{ + bool success{}; + const std::string serialized_ado{'\x01', '\x03', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', + 'H', 'L', 'O', '\x0b', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x8c', '\xb6', '4', '\x9f', 'Q', '\xda', + 'e', '\x99', '\xfe', '\xea', '\xe7', '\xc0', '\x07', 'r', '\x93', 'C', 'n', '\xb6', '\xa5', '\x00', '\x0f', '\x0e', 'n', 'p', 'n', 'w', '\x88', 'k', '\xb5', '@', '\xe2', '\xc1', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xc3', 'q', '\xf6', '\x0d', '\xd8', '3', '2', '\x98', '\xc6', '\xaa', 't', 'k', 'q', '\xe1', '\xe2', '\x05', '\'', '\xb1', '\xff', + '^', '\x1b', '\xed', 'N', '\xa9', '\xb5', '\xf5', '\x92', '\xfa', '\xdf', '\x90', '\xed', 'k'}; + + crypto::point_t expected_point_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::native, serialized_ado)}; + + ASSERT_TRUE(ado.has_value() && ado->opt_descriptor.has_value()); + ASSERT_EQ(ado->version, 1); + ASSERT_EQ(ado->opt_descriptor->version, 0); + ASSERT_EQ(ado->operation_type, ASSET_DESCRIPTOR_OPERATION_UPDATE); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); + ASSERT_TRUE(success); + success = expected_point_asset_id.from_string("c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_point_asset_id.to_public_key()); + + std::string reserialized_ado = t_serializable_object_to_blob(ado.value()); + ASSERT_EQ(serialized_ado, reserialized_ado); +} + +TEST(multiassets, native_serialization_get_or_calculate_asset_id_public_burn) +{ + bool success{}; + const std::string serialized_ado{'\x01', '\x04', '\x00', 'd', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', + 'H', 'L', 'O', '\x0b', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x0c', '@', '\x8c', '\xf8', '\xb7', '\xfb', + '\x80', '\x8f', '@', 'Y', '=', 'n', '\xb7', 'X', '\x90', '\xe2', '\xab', '=', '\x0c', '\xcd', '\xc7', '\x01', 'J', '\x7f', '\xc6', '\xb6', '\xab', '\x05', '\x16', ';', '\xe0', '`', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'T', '\xf3', '\xf7', ',', 'r', '\xe5', '\xb0', '\x14', '\xad', '+', '+', '\x90', '\x01', '\xac', '\xef', '\x95', 'O', '\xe8', '-', + '\xd3', '\xed', 'V', '\xa3', '\x8c', '\xd9', '\xdd', '\xc5', '\xdb', 'W', 'g', '?', '\x8f'}; + + crypto::point_t expected_point_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::native, serialized_ado)}; + + ASSERT_TRUE(ado.has_value() && ado->opt_descriptor.has_value()); + ASSERT_EQ(ado->version, 1); + ASSERT_EQ(ado->opt_descriptor->version, 0); + ASSERT_EQ(ado->operation_type, ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); + ASSERT_TRUE(success); + success = expected_point_asset_id.from_string("54f3f72c72e5b014ad2b2b9001acef954fe82dd3ed56a38cd9ddc5db57673f8f"); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + ASSERT_EQ(calculated_asset_id, expected_point_asset_id.to_public_key()); + + std::string reserialized_ado = t_serializable_object_to_blob(ado.value()); + ASSERT_EQ(serialized_ado, reserialized_ado); +} + + +#if 0 +TEST(multiassets, boost_serialization_get_or_calculate_asset_id_undefined) +{ + bool success{}; + const std::string serialized_ado{'\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', 'i', + 'v', 'e', '\x14', '\x00', '\x04', '\x04', '\x04', '\x08', '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', + '\x0b', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', + 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xe9', '\x1b', '\x9a', 's', ')', '-', + 'n', '\xa4', 'o', '\xb3', '\xd4', '\xf4', '\xcc', 'y', '\xc3', 'K', '\xfb', '}', '\x14', '\xc2', '\xe6', '\x84', '\xe5', '\x80', '\x93', '\xa2', 'G', '\x1c', '\x92', '\xe5', '\x1c', '\x16', + '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x97', '\x9e', '\xb7', '\x06', '\xac', '\xe2', '\xeb', '\x83', '\xf9', '\x12', 'V', 'X', '\xb2', '?', '\xb3', 'R', ' ', '\x84', '\x80', '\xcb', ';', + '\x90', '\xc4', '>', '-', '\xf0', '\xd2', '\x98', '\xf9', 'u', 'N', '\xbc'}; + + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::boost, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the boost serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_UNDEFINED); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_FALSE(success); } -TEST(multiassets, get_or_calculate_asset_id_register_boost_serialization) +TEST(multiassets, boost_serialization_get_or_calculate_asset_id_register) { - bool success{false}; - currency::asset_descriptor_operation asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', - 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', - 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', - 'i', 'v', 'e', '\x11', '\x00', '\x04', '\x08', '\x04', '\x08', - '\x01', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x01', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', '\x0b', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', - 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', - 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', - 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xcf', '\x93', '\xbe', - '\xad', 'M', '*', '\x8d', 'm', '\x17', 'L', '\x17', 'R', - '#', '{', '.', 'R', '\x08', '\xa5', '\x94', '\xb5', '\x96', - '\x18', 'h', '>', '\xe5', '\x0e', '\xf2', '\x09', '\xcf', '\x1e', - '\xfb', '\x19', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; + bool success{}; + const std::string serialized_ado{'\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', 'i', + 'v', 'e', '\x14', '\x00', '\x04', '\x04', '\x04', '\x08', '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', + '\x0b', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', + 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xcf', '\x93', '\xbe', '\xad', 'M', + '*', '\x8d', 'm', '\x17', 'L', '\x17', 'R', '#', '{', '.', 'R', '\x08', '\xa5', '\x94', '\xb5', '\x96', '\x18', 'h', '>', '\xe5', '\x0e', '\xf2', '\x09', '\xcf', '\x1e', '\xfb', '\x19', '\x00', + ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; - success = tools::unserialize_obj_from_buff( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::boost, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the boost serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + success = expected_point_asset_id.from_string("6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_emit_boost_serialization) +TEST(multiassets, boost_serialization_get_or_calculate_asset_id_emit) { - bool success{false}; - currency::asset_descriptor_operation asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', - 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', - 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', - 'i', 'v', 'e', '\x11', '\x00', '\x04', '\x08', '\x04', '\x08', - '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x02', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', '\x0b', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', - 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', - 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', - 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xed', '\xab', 'W', - '\x1c', 'K', '\xe9', '\xea', '\xbf', '\xea', '^', 'x', '\x83', - '\x03', 'm', 't', 'L', '\x09', 's', '\x82', '\xeb', 'o', - 's', '\x9a', '\x91', 'M', '\xb0', 'o', 'r', '\xba', '5', - '\x09', '\x9d', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', - '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', 'I', '\xa3', '\xd6', 'e', '*', '\xaa', - '\x0b', ';', 'w', ')', ',', 'S', 'N', '\x91', '\xff', - '\x80', '\xde', '\x91', ' ', '\xae', '\xb6', '\xfc', '\x1c', '^', - '\xdc', 'r', '\x80', 'G', 'C', '}', 'f', '~'}; + bool success{}; + const std::string serialized_ado{'\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', 'i', + 'v', 'e', '\x14', '\x00', '\x04', '\x04', '\x04', '\x08', '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x02', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', + '\x0b', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', + 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xed', '\xab', 'W', '\x1c', 'K', + '\xe9', '\xea', '\xbf', '\xea', '^', 'x', '\x83', '\x03', 'm', 't', 'L', '\x09', 's', '\x82', '\xeb', 'o', 's', '\x9a', '\x91', 'M', '\xb0', 'o', 'r', '\xba', '5', '\x09', '\x9d', '\x00', ' ', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', 'I', '\xa3', '\xd6', 'e', '*', '\xaa', '\x0b', ';', 'w', ')', ',', 'S', 'N', '\x91', '\xff', '\x80', '\xde', '\x91', ' ', '\xae', '\xb6', '\xfc', '\x1c', '^', + '\xdc', 'r', '\x80', 'G', 'C', '}', 'f', '~'}; - success = tools::unserialize_obj_from_buff( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::boost, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the boost serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_EMIT); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + success = expected_point_asset_id.from_string("49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_update_boost_serialization) +TEST(multiassets, boost_serialization_get_or_calculate_asset_id_update) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', - 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', - 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', - 'i', 'v', 'e', '\x11', '\x00', '\x04', '\x08', '\x04', '\x08', - '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', '\x0b', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', - 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', - 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', - 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x8c', '\xb6', '4', - '\x9f', 'Q', '\xda', 'e', '\x99', '\xfe', '\xea', '\xe7', '\xc0', - '\x07', 'r', '\x93', 'C', 'n', '\xb6', '\xa5', '\x00', '\x0f', - '\x0e', 'n', 'p', 'n', 'w', '\x88', 'k', '\xb5', '@', - '\xe2', '\xc1', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', - '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\xc3', 'q', '\xf6', '\x0d', '\xd8', '3', - '2', '\x98', '\xc6', '\xaa', 't', 'k', 'q', '\xe1', '\xe2', - '\x05', '\'', '\xb1', '\xff', '^', '\x1b', '\xed', 'N', '\xa9', - '\xb5', '\xf5', '\x92', '\xfa', '\xdf', '\x90', '\xed', 'k'}; + bool success{}; + const std::string serialized_ado{'\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', 'i', + 'v', 'e', '\x14', '\x00', '\x04', '\x04', '\x04', '\x08', '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', + '\x0b', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', + 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x8c', '\xb6', '4', '\x9f', 'Q', + '\xda', 'e', '\x99', '\xfe', '\xea', '\xe7', '\xc0', '\x07', 'r', '\x93', 'C', 'n', '\xb6', '\xa5', '\x00', '\x0f', '\x0e', 'n', 'p', 'n', 'w', '\x88', 'k', '\xb5', '@', '\xe2', '\xc1', '\x00', + ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\xc3', 'q', '\xf6', '\x0d', '\xd8', '3', '2', '\x98', '\xc6', '\xaa', 't', 'k', 'q', '\xe1', '\xe2', '\x05', '\'', '\xb1', '\xff', '^', '\x1b', '\xed', 'N', + '\xa9', '\xb5', '\xf5', '\x92', '\xfa', '\xdf', '\x90', '\xed', 'k'}; - success = tools::unserialize_obj_from_buff( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::boost, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the boost serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_UPDATE); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + success = expected_point_asset_id.from_string("c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_public_burn_boost_serialization) +TEST(multiassets, boost_serialization_get_or_calculate_asset_id_public_burn) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', - 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', - 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', - 'i', 'v', 'e', '\x11', '\x00', '\x04', '\x08', '\x04', '\x08', - '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x04', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', '\x0b', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', - 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', - 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', - 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0c', '@', '\x8c', - '\xf8', '\xb7', '\xfb', '\x80', '\x8f', '@', 'Y', '=', 'n', - '\xb7', 'X', '\x90', '\xe2', '\xab', '=', '\x0c', '\xcd', '\xc7', - '\x01', 'J', '\x7f', '\xc6', '\xb6', '\xab', '\x05', '\x16', ';', - '\xe0', '`', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', - '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', 'T', '\xf3', '\xf7', ',', 'r', '\xe5', - '\xb0', '\x14', '\xad', '+', '+', '\x90', '\x01', '\xac', '\xef', - '\x95', 'O', '\xe8', '-', '\xd3', '\xed', 'V', '\xa3', '\x8c', - '\xd9', '\xdd', '\xc5', '\xdb', 'W', 'g', '?', '\x8f'}; + bool success{}; + const std::string serialized_ado{'\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', 'i', + 'v', 'e', '\x14', '\x00', '\x04', '\x04', '\x04', '\x08', '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x04', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', + '\x0b', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', + 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x0c', '@', '\x8c', '\xf8', '\xb7', + '\xfb', '\x80', '\x8f', '@', 'Y', '=', 'n', '\xb7', 'X', '\x90', '\xe2', '\xab', '=', '\x0c', '\xcd', '\xc7', '\x01', 'J', '\x7f', '\xc6', '\xb6', '\xab', '\x05', '\x16', ';', '\xe0', '`', '\x00', + ' ', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', 'T', '\xf3', '\xf7', ',', 'r', '\xe5', '\xb0', '\x14', '\xad', '+', '+', '\x90', '\x01', '\xac', '\xef', '\x95', 'O', '\xe8', '-', '\xd3', '\xed', 'V', '\xa3', + '\x8c', '\xd9', '\xdd', '\xc5', '\xdb', 'W', 'g', '?', '\x8f'}; - success = tools::unserialize_obj_from_buff( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::boost, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the boost serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + success = expected_point_asset_id.from_string("54f3f72c72e5b014ad2b2b9001acef954fe82dd3ed56a38cd9ddc5db57673f8f"); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "54f3f72c72e5b014ad2b2b9001acef954fe82dd3ed56a38cd9ddc5db57673f8f"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_undefined_boost_serialization) +TEST(multiassets, key_value_serialization_get_or_calculate_asset_id_undefined) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '\x16', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 's', - 'e', 'r', 'i', 'a', 'l', 'i', 'z', 'a', 't', - 'i', 'o', 'n', ':', ':', 'a', 'r', 'c', 'h', - 'i', 'v', 'e', '\x11', '\x00', '\x04', '\x08', '\x04', '\x08', - '\x01', '\x00', '\x00', '\x00', '\x00', '\x01', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'd', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '2', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x03', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', 'H', 'L', 'O', '\x0b', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'E', 'L', - 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '\x0d', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', 'H', 'e', - 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', - 'd', '!', '\x00', '\x00', '\x00', '\x00', '\x00', ' ', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\xe9', '\x1b', '\x9a', - 's', ')', '-', 'n', '\xa4', 'o', '\xb3', '\xd4', '\xf4', - '\xcc', 'y', '\xc3', 'K', '\xfb', '}', '\x14', '\xc2', '\xe6', - '\x84', '\xe5', '\x80', '\x93', '\xa2', 'G', '\x1c', '\x92', '\xe5', - '\x1c', '\x16', '\x00', ' ', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x01', - '\x00', '\x00', '\x00', '\x01', ' ', '\x00', '\x00', '\x00', '\x00', - '\x00', '\x00', '\x00', '\x97', '\x9e', '\xb7', '\x06', '\xac', '\xe2', - '\xeb', '\x83', '\xf9', '\x12', 'V', 'X', '\xb2', '?', '\xb3', - 'R', ' ', '\x84', '\x80', '\xcb', ';', '\x90', '\xc4', '>', - '-', '\xf0', '\xd2', '\x98', '\xf9', 'u', 'N', '\xbc'}; + bool success{}; + const std::string serialized_ado{'{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '"', + ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', + 'd', 'e', 'c', 'i', 'm', 'a', 'l', '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', '"', ':', ' ', '"', + 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', 'f', 'a', + 'l', 's', 'e', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', + ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', 'n', 'e', 'r', '"', ':', ' ', '"', 'e', '9', '1', 'b', '9', 'a', '7', '3', '2', '9', '2', 'd', '6', 'e', 'a', '4', '6', 'f', 'b', '3', 'd', + '4', 'f', '4', 'c', 'c', '7', '9', 'c', '3', '4', 'b', 'f', 'b', '7', 'd', '1', '4', 'c', '2', 'e', '6', '8', '4', 'e', '5', '8', '0', '9', '3', 'a', '2', '4', '7', '1', 'c', '9', '2', 'e', '5', + '1', 'c', '1', '6', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'o', + 't', 'a', 'l', '_', 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 'e', 'r', 'a', 't', + 'i', 'o', 'n', '_', 't', 'y', 'p', 'e', '"', ':', ' ', '0', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', '"', ':', ' ', '"', '9', '7', '9', 'e', + 'b', '7', '0', '6', 'a', 'c', 'e', '2', 'e', 'b', '8', '3', 'f', '9', '1', '2', '5', '6', '5', '8', 'b', '2', '3', 'f', 'b', '3', '5', '2', '2', '0', '8', '4', '8', '0', 'c', 'b', '3', 'b', '9', + '0', 'c', '4', '3', 'e', '2', 'd', 'f', '0', 'd', '2', '9', '8', 'f', '9', '7', '5', '4', 'e', 'b', 'c', '"', '\x0d', '\x0a', '}'}; - success = tools::unserialize_obj_from_buff( - asset_descriptor_operation, - serialized_asset_descriptor_operation); - ASSERT_TRUE(success); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::key_value, serialized_ado)}; - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the key-value serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_UNDEFINED); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_FALSE(success); } -TEST(multiassets, get_or_calculate_asset_id_register_key_value_serialization) +TEST(multiassets, key_value_serialization_get_or_calculate_asset_id_register) { - bool success{false}; - currency::asset_descriptor_operation asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', - 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', - 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', - 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', - '"', ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', - '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', - ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'd', 'e', 'c', 'i', 'm', 'a', 'l', - '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', - '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', - 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', - '"', ':', ' ', '"', 'H', 'E', 'L', 'L', 'O', - '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', - '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', - 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', 'f', 'a', 'l', 's', 'e', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', - 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', - ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', - ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', ',', - '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', - 'n', 'e', 'r', '"', ':', ' ', '"', 'c', 'f', - '9', '3', 'b', 'e', 'a', 'd', '4', 'd', '2', - 'a', '8', 'd', '6', 'd', '1', '7', '4', 'c', - '1', '7', '5', '2', '2', '3', '7', 'b', '2', - 'e', '5', '2', '0', '8', 'a', '5', '9', '4', - 'b', '5', '9', '6', '1', '8', '6', '8', '3', - 'e', 'e', '5', '0', 'e', 'f', '2', '0', '9', - 'c', 'f', '1', 'e', 'f', 'b', '1', '9', '"', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', - 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', - 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', - ' ', ' ', '"', 't', 'o', 't', 'a', 'l', '_', - 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', - ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', - 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', - '_', 't', 'y', 'p', 'e', '"', ':', ' ', '1', - ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', - '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', - '"', ':', ' ', '"', '0', '1', '6', 'f', '4', - '6', '3', '2', '4', 'f', 'a', 'a', 'e', '4', - '4', '8', 'b', '9', 'e', '3', 'b', '9', '6', - 'd', 'a', 'c', '9', '4', 'd', 'a', '1', '7', - 'b', 'e', '6', 'a', 'b', '7', 'e', 'a', 'a', - 'b', 'a', '3', '9', '8', 'd', 'e', '8', '6', - 'd', '8', '7', '4', '3', '0', '4', '2', 'c', - '9', '8', 'b', 'a', 'c', 'e', '0', '"', '\x0d', - '\x0a', '}'}; + bool success{}; + const std::string serialized_ado{'{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '"', + ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', + 'd', 'e', 'c', 'i', 'm', 'a', 'l', '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', '"', ':', ' ', '"', + 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', 'f', 'a', + 'l', 's', 'e', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', + ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', 'n', 'e', 'r', '"', ':', ' ', '"', 'c', 'f', '9', '3', 'b', 'e', 'a', 'd', '4', 'd', '2', 'a', '8', 'd', '6', 'd', '1', '7', '4', 'c', '1', + '7', '5', '2', '2', '3', '7', 'b', '2', 'e', '5', '2', '0', '8', 'a', '5', '9', '4', 'b', '5', '9', '6', '1', '8', '6', '8', '3', 'e', 'e', '5', '0', 'e', 'f', '2', '0', '9', 'c', 'f', '1', 'e', + 'f', 'b', '1', '9', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'o', + 't', 'a', 'l', '_', 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 'e', 'r', 'a', 't', + 'i', 'o', 'n', '_', 't', 'y', 'p', 'e', '"', ':', ' ', '1', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', '"', ':', ' ', '"', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '"', '\x0d', '\x0a', '}'}; - success = epee::serialization::load_t_from_json( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::key_value, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the key-value serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_REGISTER); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + success = expected_point_asset_id.from_string("6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "6f46324faae448b9e3b96dac94da17be6ab7eaaba398de86d8743042c98bace0"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - const crypto::public_key expected_asset_id_key{ - expected_asset_id_pt.to_public_key()}; - - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_emit_key_value_serialization) +TEST(multiassets, key_value_serialization_get_or_calculate_asset_id_emit) { - bool success{false}; - currency::asset_descriptor_operation asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', - 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', - 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', - 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', - '"', ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', - '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', - ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'd', 'e', 'c', 'i', 'm', 'a', 'l', - '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', - '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', - 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', - '"', ':', ' ', '"', 'H', 'E', 'L', 'L', 'O', - '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', - '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', - 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', 'f', 'a', 'l', 's', 'e', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', - 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', - ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', - ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', ',', - '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', - 'n', 'e', 'r', '"', ':', ' ', '"', 'e', 'd', - 'a', 'b', '5', '7', '1', 'c', '4', 'b', 'e', - '9', 'e', 'a', 'b', 'f', 'e', 'a', '5', 'e', - '7', '8', '8', '3', '0', '3', '6', 'd', '7', - '4', '4', 'c', '0', '9', '7', '3', '8', '2', - 'e', 'b', '6', 'f', '7', '3', '9', 'a', '9', - '1', '4', 'd', 'b', '0', '6', 'f', '7', '2', - 'b', 'a', '3', '5', '0', '9', '9', 'd', '"', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', - 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', - 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', - ' ', ' ', '"', 't', 'o', 't', 'a', 'l', '_', - 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', - ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', - 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', - '_', 't', 'y', 'p', 'e', '"', ':', ' ', '2', - ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', - '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', - '"', ':', ' ', '"', '0', '1', '4', '9', 'a', - '3', 'd', '6', '6', '5', '2', 'a', 'a', 'a', - '0', 'b', '3', 'b', '7', '7', '2', '9', '2', - 'c', '5', '3', '4', 'e', '9', '1', 'f', 'f', - '8', '0', 'd', 'e', '9', '1', '2', '0', 'a', - 'e', 'b', '6', 'f', 'c', '1', 'c', '5', 'e', - 'd', 'c', '7', '2', '8', '0', '4', '7', '4', - '3', '7', 'd', '6', '6', '7', 'e', '"', '\x0d', - '\x0a', '}'}; + bool success{}; + const std::string serialized_ado{'{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '"', + ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', + 'd', 'e', 'c', 'i', 'm', 'a', 'l', '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', '"', ':', ' ', '"', + 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', 'f', 'a', + 'l', 's', 'e', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', + ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', 'n', 'e', 'r', '"', ':', ' ', '"', 'e', 'd', 'a', 'b', '5', '7', '1', 'c', '4', 'b', 'e', '9', 'e', 'a', 'b', 'f', 'e', 'a', '5', 'e', '7', + '8', '8', '3', '0', '3', '6', 'd', '7', '4', '4', 'c', '0', '9', '7', '3', '8', '2', 'e', 'b', '6', 'f', '7', '3', '9', 'a', '9', '1', '4', 'd', 'b', '0', '6', 'f', '7', '2', 'b', 'a', '3', '5', + '0', '9', '9', 'd', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'o', + 't', 'a', 'l', '_', 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 'e', 'r', 'a', 't', + 'i', 'o', 'n', '_', 't', 'y', 'p', 'e', '"', ':', ' ', '2', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', '"', ':', ' ', '"', '4', '9', 'a', '3', + 'd', '6', '6', '5', '2', 'a', 'a', 'a', '0', 'b', '3', 'b', '7', '7', '2', '9', '2', 'c', '5', '3', '4', 'e', '9', '1', 'f', 'f', '8', '0', 'd', 'e', '9', '1', '2', '0', 'a', 'e', 'b', '6', 'f', + 'c', '1', 'c', '5', 'e', 'd', 'c', '7', '2', '8', '0', '4', '7', '4', '3', '7', 'd', '6', '6', '7', 'e', '"', '\x0d', '\x0a', '}'}; - success = epee::serialization::load_t_from_json( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::key_value, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the key-value serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_EMIT); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + success = expected_point_asset_id.from_string("49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "49a3d6652aaa0b3b77292c534e91ff80de9120aeb6fc1c5edc728047437d667e"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_update_key_value_serialization) +TEST(multiassets, key_value_serialization_get_or_calculate_asset_id_update) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', - 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', - 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', - 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', - '"', ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', - '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', - ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'd', 'e', 'c', 'i', 'm', 'a', 'l', - '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', - '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', - 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', - '"', ':', ' ', '"', 'H', 'E', 'L', 'L', 'O', - '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', - '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', - 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', 'f', 'a', 'l', 's', 'e', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', - 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', - ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', - ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', ',', - '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', - 'n', 'e', 'r', '"', ':', ' ', '"', '8', 'c', - 'b', '6', '3', '4', '9', 'f', '5', '1', 'd', - 'a', '6', '5', '9', '9', 'f', 'e', 'e', 'a', - 'e', '7', 'c', '0', '0', '7', '7', '2', '9', - '3', '4', '3', '6', 'e', 'b', '6', 'a', '5', - '0', '0', '0', 'f', '0', 'e', '6', 'e', '7', - '0', '6', 'e', '7', '7', '8', '8', '6', 'b', - 'b', '5', '4', '0', 'e', '2', 'c', '1', '"', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', - 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', - 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', - ' ', ' ', '"', 't', 'o', 't', 'a', 'l', '_', - 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', - ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', - 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', - '_', 't', 'y', 'p', 'e', '"', ':', ' ', '3', - ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', - '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', - '"', ':', ' ', '"', '0', '1', 'c', '3', '7', - '1', 'f', '6', '0', 'd', 'd', '8', '3', '3', - '3', '2', '9', '8', 'c', '6', 'a', 'a', '7', - '4', '6', 'b', '7', '1', 'e', '1', 'e', '2', - '0', '5', '2', '7', 'b', '1', 'f', 'f', '5', - 'e', '1', 'b', 'e', 'd', '4', 'e', 'a', '9', - 'b', '5', 'f', '5', '9', '2', 'f', 'a', 'd', - 'f', '9', '0', 'e', 'd', '6', 'b', '"', '\x0d', - '\x0a', '}'}; + bool success{}; + const std::string serialized_ado{'{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '"', + ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', + 'd', 'e', 'c', 'i', 'm', 'a', 'l', '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', '"', ':', ' ', '"', + 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', 'f', 'a', + 'l', 's', 'e', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', + ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', 'n', 'e', 'r', '"', ':', ' ', '"', '8', 'c', 'b', '6', '3', '4', '9', 'f', '5', '1', 'd', 'a', '6', '5', '9', '9', 'f', 'e', 'e', 'a', 'e', + '7', 'c', '0', '0', '7', '7', '2', '9', '3', '4', '3', '6', 'e', 'b', '6', 'a', '5', '0', '0', '0', 'f', '0', 'e', '6', 'e', '7', '0', '6', 'e', '7', '7', '8', '8', '6', 'b', 'b', '5', '4', '0', + 'e', '2', 'c', '1', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'o', + 't', 'a', 'l', '_', 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 'e', 'r', 'a', 't', + 'i', 'o', 'n', '_', 't', 'y', 'p', 'e', '"', ':', ' ', '3', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', '"', ':', ' ', '"', 'c', '3', '7', '1', + 'f', '6', '0', 'd', 'd', '8', '3', '3', '3', '2', '9', '8', 'c', '6', 'a', 'a', '7', '4', '6', 'b', '7', '1', 'e', '1', 'e', '2', '0', '5', '2', '7', 'b', '1', 'f', 'f', '5', 'e', '1', 'b', 'e', + 'd', '4', 'e', 'a', '9', 'b', '5', 'f', '5', '9', '2', 'f', 'a', 'd', 'f', '9', '0', 'e', 'd', '6', 'b', '"', '\x0d', '\x0a', '}'}; - success = epee::serialization::load_t_from_json( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::key_value, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the key-value serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_UPDATE); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); + success = expected_point_asset_id.from_string("c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"); ASSERT_TRUE(success); - - const std::string expected_asset_id_str{ - "c371f60dd8333298c6aa746b71e1e20527b1ff5e1bed4ea9b5f592fadf90ed6b"}; - - crypto::point_t expected_asset_id_pt{}; - success = expected_asset_id_pt.from_string(expected_asset_id_str); - ASSERT_TRUE(success); - - crypto::public_key expected_asset_id_key{}; - expected_asset_id_pt.to_public_key(expected_asset_id_key); - ASSERT_EQ(calculated_asset_id_pt, expected_asset_id_pt); - ASSERT_EQ(calculated_asset_id_key, expected_asset_id_key); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } -TEST(multiassets, get_or_calculate_asset_id_undefined_key_value_serialization) +TEST(multiassets, key_value_serialization_get_or_calculate_asset_id_public_burn) { - bool success{false}; - currency::asset_descriptor_operation_v0 asset_descriptor_operation{}; - const std::string serialized_asset_descriptor_operation{ - '{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', - 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', - 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '0', '0', '0', '0', '0', '0', '0', '0', - '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', - 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', - '"', ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', - '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', - ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', - ' ', '"', 'd', 'e', 'c', 'i', 'm', 'a', 'l', - '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', - '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', - 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', - '"', ':', ' ', '"', 'H', 'E', 'L', 'L', 'O', - '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', - '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', - 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', 'f', 'a', 'l', 's', 'e', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', - 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', - ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', - ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', ',', - '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', - 'n', 'e', 'r', '"', ':', ' ', '"', 'e', '9', - '1', 'b', '9', 'a', '7', '3', '2', '9', '2', - 'd', '6', 'e', 'a', '4', '6', 'f', 'b', '3', - 'd', '4', 'f', '4', 'c', 'c', '7', '9', 'c', - '3', '4', 'b', 'f', 'b', '7', 'd', '1', '4', - 'c', '2', 'e', '6', '8', '4', 'e', '5', '8', - '0', '9', '3', 'a', '2', '4', '7', '1', 'c', - '9', '2', 'e', '5', '1', 'c', '1', '6', '"', - ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', - 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', - 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', - ' ', ' ', '"', 't', 'o', 't', 'a', 'l', '_', - 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', - 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', - ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', - 'o', 'p', 'e', 'r', 'a', 't', 'i', 'o', 'n', - '_', 't', 'y', 'p', 'e', '"', ':', ' ', '0', - ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', - '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', - '"', ':', ' ', '"', '0', '1', '9', '7', '9', - 'e', 'b', '7', '0', '6', 'a', 'c', 'e', '2', - 'e', 'b', '8', '3', 'f', '9', '1', '2', '5', - '6', '5', '8', 'b', '2', '3', 'f', 'b', '3', - '5', '2', '2', '0', '8', '4', '8', '0', 'c', - 'b', '3', 'b', '9', '0', 'c', '4', '3', 'e', - '2', 'd', 'f', '0', 'd', '2', '9', '8', 'f', - '9', '7', '5', '4', 'e', 'b', 'c', '"', '\x0d', - '\x0a', '}'}; + bool success{}; + const std::string serialized_ado{'{', '\x0d', '\x0a', ' ', ' ', '"', 'a', 'm', 'o', 'u', 'n', 't', '_', 'c', 'o', 'm', 'm', 'i', 't', 'm', 'e', 'n', 't', '"', ':', ' ', '"', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', + '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '"', ',', '\x0d', '\x0a', ' ', ' ', '"', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', '"', + ':', ' ', '{', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'c', 'u', 'r', 'r', 'e', 'n', 't', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '5', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', + 'd', 'e', 'c', 'i', 'm', 'a', 'l', '_', 'p', 'o', 'i', 'n', 't', '"', ':', ' ', '0', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'f', 'u', 'l', 'l', '_', 'n', 'a', 'm', 'e', '"', ':', ' ', '"', + 'H', 'E', 'L', 'L', 'O', '_', 'W', 'O', 'R', 'L', 'D', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'h', 'i', 'd', 'd', 'e', 'n', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', 'f', 'a', + 'l', 's', 'e', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'm', 'e', 't', 'a', '_', 'i', 'n', 'f', 'o', '"', ':', ' ', '"', 'H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!', '"', + ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 'o', 'w', 'n', 'e', 'r', '"', ':', ' ', '"', '0', 'c', '4', '0', '8', 'c', 'f', '8', 'b', '7', 'f', 'b', '8', '0', '8', 'f', '4', '0', '5', '9', '3', + 'd', '6', 'e', 'b', '7', '5', '8', '9', '0', 'e', '2', 'a', 'b', '3', 'd', '0', 'c', 'c', 'd', 'c', '7', '0', '1', '4', 'a', '7', 'f', 'c', '6', 'b', '6', 'a', 'b', '0', '5', '1', '6', '3', 'b', + 'e', '0', '6', '0', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'i', 'c', 'k', 'e', 'r', '"', ':', ' ', '"', 'H', 'L', 'O', '"', ',', '\x0d', '\x0a', ' ', ' ', ' ', ' ', '"', 't', 'o', + 't', 'a', 'l', '_', 'm', 'a', 'x', '_', 's', 'u', 'p', 'p', 'l', 'y', '"', ':', ' ', '1', '0', '0', '\x0d', '\x0a', ' ', ' ', '}', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 'e', 'r', 'a', 't', + 'i', 'o', 'n', '_', 't', 'y', 'p', 'e', '"', ':', ' ', '4', ',', '\x0d', '\x0a', ' ', ' ', '"', 'o', 'p', 't', '_', 'a', 's', 's', 'e', 't', '_', 'i', 'd', '"', ':', ' ', '"', '5', '4', 'f', '3', + 'f', '7', '2', 'c', '7', '2', 'e', '5', 'b', '0', '1', '4', 'a', 'd', '2', 'b', '2', 'b', '9', '0', '0', '1', 'a', 'c', 'e', 'f', '9', '5', '4', 'f', 'e', '8', '2', 'd', 'd', '3', 'e', 'd', '5', + '6', 'a', '3', '8', 'c', 'd', '9', 'd', 'd', 'c', '5', 'd', 'b', '5', '7', '6', '7', '3', 'f', '8', 'f', '"', '\x0d', '\x0a', '}'}; - success = epee::serialization::load_t_from_json( - asset_descriptor_operation, - serialized_asset_descriptor_operation); + crypto::point_t expected_point_asset_id{}; + crypto::public_key expected_asset_id{}; + crypto::point_t calculated_point_asset_id{}; + crypto::public_key calculated_asset_id{}; + const std::optional ado{deserialize(serialization_method::key_value, serialized_ado)}; + + ASSERT_TRUE(ado.has_value()); + ASSERT_EQ(ado.value().verion, 1); + /* TODO: fix the key-value serialization of the asset_descriptor_operation_v0 objects: .description.version must be equals to 0. + ASSERT_EQ(ado.value().descriptor.version, 0); */ + ASSERT_EQ(ado.value().operation_type, ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN); + success = currency::get_or_calculate_asset_id(ado.value(), &calculated_point_asset_id, &calculated_asset_id); ASSERT_TRUE(success); - - crypto::point_t calculated_asset_id_pt{}; - crypto::public_key calculated_asset_id_key{}; - - success = currency::get_or_calculate_asset_id(asset_descriptor_operation, - &calculated_asset_id_pt, - &calculated_asset_id_key); - ASSERT_FALSE(success); + success = expected_point_asset_id.from_string("54f3f72c72e5b014ad2b2b9001acef954fe82dd3ed56a38cd9ddc5db57673f8f"); + ASSERT_TRUE(success); + ASSERT_EQ(calculated_point_asset_id, expected_point_asset_id); + expected_asset_id = expected_point_asset_id.to_public_key(); + ASSERT_EQ(calculated_asset_id, expected_asset_id); } +#endif diff --git a/tests/unit_tests/p2p_client_version.cpp b/tests/unit_tests/p2p_client_version.cpp index e89817b0..c7b5f528 100644 --- a/tests/unit_tests/p2p_client_version.cpp +++ b/tests/unit_tests/p2p_client_version.cpp @@ -5,21 +5,180 @@ #include "gtest/gtest.h" #include "common/util.h" -bool check_parse_client_version(const std::string& str, int expected_major, int expected_minor, int expected_revision, int expected_build_number, const std::string& expected_commit_id, bool expected_dirty) +enum class reponse_check_parse_client_version : uint8_t { - int major = -1, minor = -1, revision = -1, build_number = -1; - std::string commit_id; - bool dirty = false; + parsed, + not_parsed, + parsed_unexpect +}; + +static reponse_check_parse_client_version check_parse_client_version(const std::string& str, const std::optional& expected_major, const std::optional& expected_minor, + const std::optional& expected_revision, const std::optional& expected_build_number, + const std::optional& expected_commit_id, const std::optional& expected_dirty) +{ + enum class version_integer_component : uint8_t { major, minor, revision, build_number }; + std::array values_on_not_written{INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN}; + int32_t major{}, minor{}, revision{}, build_number{}; + std::string commit_id{}; + bool dirty{}; + + if (expected_major.has_value() && expected_major.value() == INT32_MIN) + { + values_on_not_written.at(static_cast(version_integer_component::major)) = INT32_MAX; + } + + if (expected_minor.has_value() && expected_minor.value() == INT32_MIN) + { + values_on_not_written.at(static_cast(version_integer_component::minor)) = INT32_MAX; + } + + if (expected_revision.has_value() && expected_revision.value() == INT32_MIN) + { + values_on_not_written.at(static_cast(version_integer_component::revision)) = INT32_MAX; + } + + if (expected_build_number.has_value() && expected_build_number.value() == INT32_MIN) + { + values_on_not_written.at(static_cast(version_integer_component::build_number)) = INT32_MAX; + } + + major = values_on_not_written.at(static_cast(version_integer_component::major)); + minor = values_on_not_written.at(static_cast(version_integer_component::minor)); + revision = values_on_not_written.at(static_cast(version_integer_component::revision)); + build_number = values_on_not_written.at(static_cast(version_integer_component::build_number)); + + if (expected_commit_id.has_value() && !expected_commit_id.value().empty()) + { + const auto length{expected_commit_id.value().length()}; + + assert(length + 1 > length); + commit_id = std::string(length + 1, '\0'); + } + if (!tools::parse_client_version(str, major, minor, revision, build_number, commit_id, dirty)) - return false; + { + return reponse_check_parse_client_version::not_parsed; + } - return major == expected_major && minor == expected_minor && revision == expected_revision && build_number == expected_build_number && commit_id == expected_commit_id && dirty == expected_dirty; + if (expected_major.has_value()) + { + if (major == values_on_not_written.at(static_cast(version_integer_component::major)) || major != expected_major.value()) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + else + { + if (major != values_on_not_written.at(static_cast(version_integer_component::major))) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + if (expected_minor.has_value()) + { + if (minor == values_on_not_written.at(static_cast(version_integer_component::minor)) || minor != expected_minor.value()) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + else + { + if (minor != values_on_not_written.at(static_cast(version_integer_component::minor))) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + if (expected_revision.has_value()) + { + if (revision == values_on_not_written.at(static_cast(version_integer_component::revision)) || revision != expected_revision.value()) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + else + { + if (revision != values_on_not_written.at(static_cast(version_integer_component::revision))) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + if (expected_commit_id.has_value()) + { + if (commit_id != expected_commit_id.value()) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + else + { + if (!commit_id.empty()) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + if (expected_dirty.has_value()) + { + if (dirty != expected_dirty.value()) + { + return reponse_check_parse_client_version::parsed_unexpect; + } + } + + else + { + return reponse_check_parse_client_version::parsed_unexpect; + } + + return reponse_check_parse_client_version::parsed; } - TEST(p2p_client_version, test_0) { - ASSERT_TRUE(check_parse_client_version("10.101.999.28391[deadbeef31337-dirty]", 10, 101, 999, 28391, "deadbeef31337", true)); + ASSERT_EQ(check_parse_client_version("10.101.999.28391[deadbeef31337-dirty]", 10, 101, 999, 28391, "deadbeef31337", true), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("+67.+43.+50.+83", 67, 43, 50, 83, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-12.-90.17.-95", -12, -90, 17, -95, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("54.-100.-76.21[]", 54, -100, -76, 21, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-93.8.-81.75[-dirty]", -93, 8, -81, 75, "", true), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-8.-85.79.24[--dirty]", -8, -85, 79, 24, "-", true), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-62.53.79.80[\\]", -62, 53, 79, 80, "\\", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-27.91.-12.34[-]", -27, 91, -12, 34, "-", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-51.-66.-10.58\0[--dirty]", -51, -66, -10, 58, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-24.27.-81.79[" "\0" "-dirty]", {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); + ASSERT_EQ(check_parse_client_version("0.0.0.0", 0, 0, 0, 0, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("27 . 33 . -59 . 47", 27, 33, -59, 47, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("-2147483648.-2147483648.-2147483648.-2147483648", INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("2147483647.2147483647.2147483647.2147483647", INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, "", false), reponse_check_parse_client_version::parsed); + //ASSERT_EQ(check_parse_client_version("2147483648.2147483648.2147483648.2147483648", INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, "", false), reponse_check_parse_client_version::parsed); + //ASSERT_EQ(check_parse_client_version("-2147483649.-2147483649.-2147483649.-2147483649", INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("0098.+0096.0081.-0056", 98, 96, 81, -56, "", false), reponse_check_parse_client_version::parsed); + ASSERT_EQ(check_parse_client_version("\0" "38.67.31.-24", 38, 67, 31, -24, "", false), reponse_check_parse_client_version::not_parsed); + ASSERT_EQ(check_parse_client_version({'-', '6', '8', '.', '\0', '2', '9', '.', '5', '9', '.', '-', '7', '9'}, {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); + ASSERT_EQ(check_parse_client_version("....", {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); + ASSERT_EQ(check_parse_client_version("54.12.-10", {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); + ASSERT_EQ(check_parse_client_version("-.-.-.-", {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); + ASSERT_EQ(check_parse_client_version(" . . . ", {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); + + ASSERT_EQ(check_parse_client_version({'-', '2', '3', '.', '6', '.', '-', '1', '8', '.', '-', '1', '1', '[', '\0', ']'}, -23, 6, -18, -11, std::string{'\0'}, false), + reponse_check_parse_client_version::parsed); + + ASSERT_EQ(check_parse_client_version({'9', '8', '.', '3', '.', '8', '9', '.', '-', '1', '[', '\0', '-', 'd', 'i','r', 't', 'y', ']'}, 98, 3, 89, -1, std::string{'\0'}, true), + reponse_check_parse_client_version::parsed); + + //ASSERT_EQ(check_parse_client_version("5.42.25.-42[].", 5, 42, 25, -42, "", false), reponse_check_parse_client_version::parsed); + //ASSERT_EQ(check_parse_client_version("-84.91.-10.1[-dirty].", 5, 42, 25, -42, "", true), reponse_check_parse_client_version::parsed); + //ASSERT_EQ(check_parse_client_version("33.62.-92.-44.", 33, 62, -92, -44, "", false), reponse_check_parse_client_version::parsed); + //ASSERT_EQ(check_parse_client_version("...", {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); + //ASSERT_EQ(check_parse_client_version("-80.28.-6.1[", -80, 28, -6, 1, "", false), reponse_check_parse_client_version::parsed); + //ASSERT_EQ(check_parse_client_version("-88.-36.11.-25[", -80, 28, -6, 1, "", false), reponse_check_parse_client_version::parsed); + //ASSERT_EQ(check_parse_client_version("0.0.0.[]", {}, {}, {}, {}, {}, {}), reponse_check_parse_client_version::not_parsed); } diff --git a/tests/unit_tests/prepare_outputs_entries_for_key_offsets.cpp b/tests/unit_tests/prepare_outputs_entries_for_key_offsets.cpp new file mode 100644 index 00000000..d8baa9b6 --- /dev/null +++ b/tests/unit_tests/prepare_outputs_entries_for_key_offsets.cpp @@ -0,0 +1,139 @@ +#include "gtest/gtest.h" +#include "currency_core/currency_format_utils_abstract.h" +#include "currency_core/currency_format_utils_transactions.h" + +TEST(prepare_outputs_for_key_offsets, size_lower_than_2) +{ + for (size_t size{}; size < 2; ++size) + { + std::vector outputs(size); + size_t index{SIZE_MAX}; + + ASSERT_EQ(currency::prepare_outputs_entries_for_key_offsets(outputs, 0, index), outputs); + ASSERT_EQ(index, 0); + } +} + +TEST(prepare_outputs_for_key_offsets, pass_index_greater_or_equal_to_length_of_outputs_container) +{ + const std::vector outputs(2); + + { + auto index{crypto::rand()}; + const auto index_before_preparing_outputs{index}; + + ASSERT_TRUE(currency::prepare_outputs_entries_for_key_offsets(outputs, outputs.size(), index).empty()); + ASSERT_EQ(index, index_before_preparing_outputs); + } + + { + auto index{crypto::rand()}; + const auto index_before_preparing_outputs{index}; + + ASSERT_TRUE(currency::prepare_outputs_entries_for_key_offsets(outputs, outputs.size() + 1, index).empty()); + ASSERT_EQ(index, index_before_preparing_outputs); + } + + { + auto index{crypto::rand()}; + const auto index_before_preparing_outputs{index}; + + ASSERT_TRUE(currency::prepare_outputs_entries_for_key_offsets(outputs, SIZE_MAX - 1, index).empty()); + ASSERT_EQ(index, index_before_preparing_outputs); + } + + { + auto index{crypto::rand()}; + const auto index_before_preparing_outputs{index}; + + ASSERT_EQ(currency::prepare_outputs_entries_for_key_offsets(outputs, SIZE_MAX, index), outputs); + ASSERT_EQ(index, index_before_preparing_outputs); + } +} + +TEST(prepare_outputs_for_key_offsets, uint64_reference_lower_than_by_id_reference) +{ + std::vector outputs{}, expected_prepared_outputs{}; + size_t index{}; + + outputs.reserve(2); + outputs.emplace_back(currency::ref_by_id{}, currency::null_pkey); + outputs.emplace_back(0, currency::null_pkey); + expected_prepared_outputs.reserve(outputs.size()); + expected_prepared_outputs.emplace_back(0, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{}, currency::null_pkey); + ASSERT_EQ(outputs.size(), expected_prepared_outputs.size()); + ASSERT_EQ(currency::prepare_outputs_entries_for_key_offsets(outputs, 0, index), expected_prepared_outputs); + ASSERT_EQ(index, 1); +} + +TEST(prepare_outputs_for_key_offsets, subsequence_of_ref_by_id_references_is_not_changed) +{ + { + std::vector outputs{}, expected_prepared_outputs{}; + size_t index{}; + + outputs.reserve(6); + outputs.emplace_back(3, currency::null_pkey); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 1}, currency::null_pkey); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 0}, currency::null_pkey); + outputs.emplace_back(2, currency::null_pkey); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 3}, currency::null_pkey); + outputs.emplace_back(1, currency::null_pkey); + expected_prepared_outputs.reserve(outputs.size()); + expected_prepared_outputs.emplace_back(1, currency::null_pkey); + expected_prepared_outputs.emplace_back(1, currency::null_pkey); + expected_prepared_outputs.emplace_back(1, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 1}, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 0}, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 3}, currency::null_pkey); + ASSERT_EQ(outputs.size(), expected_prepared_outputs.size()); + ASSERT_EQ(currency::prepare_outputs_entries_for_key_offsets(outputs, 0, index), expected_prepared_outputs); + ASSERT_EQ(index, 2); + } + + { + std::vector outputs{}, expected_prepared_outputs{}; + size_t index{}; + + outputs.reserve(5); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 1}, currency::null_pkey); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 0}, currency::null_pkey); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 3}, currency::null_pkey); + outputs.emplace_back(1, currency::null_pkey); + outputs.emplace_back(0, currency::null_pkey); + expected_prepared_outputs.reserve(outputs.size()); + expected_prepared_outputs.emplace_back(0, currency::null_pkey); + expected_prepared_outputs.emplace_back(1, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 1}, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 0}, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 3}, currency::null_pkey); + ASSERT_EQ(outputs.size(), expected_prepared_outputs.size()); + ASSERT_EQ(currency::prepare_outputs_entries_for_key_offsets(outputs, 0, index), expected_prepared_outputs); + ASSERT_EQ(outputs.at(0), expected_prepared_outputs.at(2)); + ASSERT_EQ(index, 2); + } +} + +TEST(prepare_outputs_for_key_offsets, index_will_not_be_changed_if_old_index_is_size_max) +{ + std::vector outputs{}, expected_prepared_outputs{}; + auto index{crypto::rand()}; + const auto index_before_preparing_outputs{index}; + + outputs.reserve(5); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 1}, currency::null_pkey); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 0}, currency::null_pkey); + outputs.emplace_back(currency::ref_by_id{currency::null_hash, 3}, currency::null_pkey); + outputs.emplace_back(1, currency::null_pkey); + outputs.emplace_back(0, currency::null_pkey); + expected_prepared_outputs.reserve(outputs.size()); + expected_prepared_outputs.emplace_back(0, currency::null_pkey); + expected_prepared_outputs.emplace_back(1, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 1}, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 0}, currency::null_pkey); + expected_prepared_outputs.emplace_back(currency::ref_by_id{currency::null_hash, 3}, currency::null_pkey); + ASSERT_EQ(outputs.size(), expected_prepared_outputs.size()); + ASSERT_EQ(currency::prepare_outputs_entries_for_key_offsets(outputs, SIZE_MAX, index), expected_prepared_outputs); + ASSERT_EQ(index, index_before_preparing_outputs); +} diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index bd53b009..fd0807b5 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -26,10 +26,12 @@ struct Struct char blob[8]; }; - -std::ostream& operator <<(std::ostream& o, const currency::signature_v& v) +namespace currency { - return o; + ostream& operator<<(ostream& stream, [[maybe_unused]] const currency::signature_v& signature) + { + return stream; + } } template @@ -902,4 +904,4 @@ TEST(Serialization, versioning2) r = perform_test_ser_vers(a_3); ASSERT_TRUE(r); -} \ No newline at end of file +} diff --git a/tests/unit_tests/wallet_seed_test.cpp b/tests/unit_tests/wallet_seed_test.cpp index cfd6b860..b798b7c3 100644 --- a/tests/unit_tests/wallet_seed_test.cpp +++ b/tests/unit_tests/wallet_seed_test.cpp @@ -158,17 +158,18 @@ TEST(wallet_seed, basic_test) { //generate random password std::string pass = epee::string_tools::pod_to_hex(crypto::cn_fast_hash(&j, sizeof(j))); - if (j!= 0 && j < 64) - { - pass.resize(j); - } + pass.resize(std::min(j, (size_t)40)); + //get secured seed std::string secured_seed = acc.get_seed_phrase(pass); - //try to restore it without password(should fail) - currency::account_base acc2; - bool r_fail = acc2.restore_from_seed_phrase(secured_seed, ""); - ASSERT_EQ(r_fail, false); + currency::account_base acc2{}; + if (!pass.empty()) + { + //try to restore it without password(should fail) + bool r_fail = acc2.restore_from_seed_phrase(secured_seed, ""); + ASSERT_EQ(r_fail, false); + } //try to restore it with wrong password bool r_fake_pass = acc2.restore_from_seed_phrase(secured_seed, "fake_password"); @@ -182,7 +183,8 @@ TEST(wallet_seed, basic_test) currency::account_base acc3; bool r_true_res = acc3.restore_from_seed_phrase(secured_seed, pass); ASSERT_EQ(true, r_true_res); - ASSERT_EQ(true, acc3.get_keys() == acc.get_keys()); + r = acc3.get_keys() == acc.get_keys(); + ASSERT_TRUE(r); } }