1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' into merge_develop_mobile

This commit is contained in:
cryptozoidberg 2024-02-21 18:25:34 +04:00
commit 390adb3e26
No known key found for this signature in database
GPG key ID: 2E10CC61CAC8F36D
48 changed files with 1753 additions and 557 deletions

3
.gitignore vendored
View file

@ -5,4 +5,5 @@
._.DS_Store
Thumbs.db
._*
.idea
.idea
.vs/*

View file

@ -102,7 +102,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
endif()
if(MSVC)
add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /D__SSE4_1__")
add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0")
add_compile_options(/bigobj /Zm1000 /Z7 /MP2 /W3 /GS- /wd4996 /wd4503 /wd4345 /wd4091 /FIinline_c.h)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib crypt32.lib")
if(STATIC)
@ -224,7 +224,7 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
elseif(APPLE)
find_package(Boost 1.71 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
else()
find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale log)
endif()
@ -246,7 +246,7 @@ elseif(NOT MSVC)
endif()
if(BUILD_GUI)
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.1)
find_package(Qt5Widgets REQUIRED)
endif()

View file

@ -28,7 +28,7 @@ endif()
set_property(TARGET upnpc-static mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat PROPERTY FOLDER "unused")
if(MSVC)
set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused")
#set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused")
endif()

View file

@ -45,61 +45,6 @@ if(CC_HAS_VISIBILITY AND (LTO_ENABLED OR INTERPROCEDURAL_OPTIMIZATION))
set_target_properties(mdbx PROPERTIES LINK_FLAGS "-fvisibility=hidden")
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
if(MSVC)
if(NOT MSVC_LIB_EXE)
# Find lib.exe
get_filename_component(CL_NAME ${CMAKE_C_COMPILER} NAME)
string(REPLACE cl.exe lib.exe MSVC_LIB_EXE ${CL_NAME})
find_program(MSVC_LIB_EXE ${MSVC_LIB_EXE})
endif()
if(MSVC_LIB_EXE)
message(STATUS "Found MSVC's lib tool: ${MSVC_LIB_EXE}")
set(MDBX_NTDLL_EXTRA_IMPLIB ${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.lib)
add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB}
COMMENT "Create extra-import-library for ntdll.dll"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def"
COMMAND ${MSVC_LIB_EXE} /def:"${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" /out:"${MDBX_NTDLL_EXTRA_IMPLIB}" ${INITIAL_CMAKE_STATIC_LINKER_FLAGS})
else()
message(SEND_ERROR "MSVC's lib tool not found")
endif()
elseif(MINGW OR MINGW64)
if(NOT DLLTOOL)
# Find dlltool
get_filename_component(GCC_NAME ${CMAKE_C_COMPILER} NAME)
string(REPLACE gcc dlltool DLLTOOL_NAME ${GCC_NAME})
find_program(DLLTOOL NAMES ${DLLTOOL_NAME})
endif()
if(DLLTOOL)
message(STATUS "Found dlltool: ${DLLTOOL}")
set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.a")
add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB}
COMMENT "Create extra-import-library for ntdll.dll"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def"
COMMAND ${DLLTOOL} -d "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}")
else()
message(SEND_ERROR "dlltool not found")
endif()
endif()
endif()
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ${CMAKE_THREAD_LIBS_INIT})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll.lib)
if(MDBX_NTDLL_EXTRA_IMPLIB)
# LY: Sometimes Cmake requires a nightmarish magic for simple things.
# 1) create a target out of the library compilation result
add_custom_target(ntdll_extra_target DEPENDS ${MDBX_NTDLL_EXTRA_IMPLIB})
# 2) create an library target out of the library compilation result
add_library(ntdll_extra STATIC IMPORTED GLOBAL)
add_dependencies(ntdll_extra ntdll_extra_target)
# 3) specify where the library is (and where to find the headers)
set_target_properties(ntdll_extra
PROPERTIES
IMPORTED_LOCATION ${MDBX_NTDLL_EXTRA_IMPLIB})
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll_extra)
endif()
endif()
set_target_properties(mdbx PROPERTIES
INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>

View file

@ -509,6 +509,10 @@ namespace misc_utils
}
}
void UNSUBSCRIBE_ALL()
{
m_callbacks.clear();
}
template<typename param_t>
void RAISE_DEBUG_EVENT(const param_t& p)

View file

@ -137,11 +137,17 @@ namespace tools
STACKFRAME64 frame;
memset(&frame, 0, sizeof frame);
#ifndef _M_ARM64
frame.AddrPC.Offset = context.Rip;
#endif
frame.AddrPC.Mode = AddrModeFlat;
#ifndef _M_ARM64
frame.AddrStack.Offset = context.Rsp;
#endif
frame.AddrStack.Mode = AddrModeFlat;
#ifndef _M_ARM64
frame.AddrFrame.Offset = context.Rbp;
#endif
frame.AddrFrame.Mode = AddrModeFlat;
IMAGEHLP_LINE64 line = { 0 };

View file

@ -37,6 +37,7 @@ namespace command_line
const arg_descriptor<bool> arg_no_predownload ( "no-predownload", "Do not pre-download blockchain database");
const arg_descriptor<bool> arg_force_predownload ( "force-predownload", "Pre-download blockchain database regardless of it's status");
const arg_descriptor<std::string> arg_process_predownload_from_path("predownload-from-local-path", "Instead of downloading file use downloaded local file");
const arg_descriptor<bool> arg_validate_predownload ( "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database");
const arg_descriptor<std::string> arg_predownload_link ( "predownload-link", "Override url for blockchain database pre-downloading");

View file

@ -229,6 +229,7 @@ namespace command_line
extern const arg_descriptor<std::string> arg_db_engine;
extern const arg_descriptor<bool> arg_no_predownload;
extern const arg_descriptor<bool> arg_force_predownload;
extern const arg_descriptor<std::string> arg_process_predownload_from_path;
extern const arg_descriptor<bool> arg_validate_predownload;
extern const arg_descriptor<std::string> arg_predownload_link;
extern const arg_descriptor<std::string> arg_deeplink;

View file

@ -104,15 +104,15 @@ namespace crypto
FIELD((std::vector<scalar_t>&)(r_x))
FIELD(K1)
FIELD(K2)
END_SERIALIZE()
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_g))
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_x))
BOOST_SERIALIZE(K1)
BOOST_SERIALIZE(K2)
END_BOOST_SERIALIZATION()
END_BOOST_SERIALIZATION()
};
struct CLSAG_GGXXG_signature_serialized : public CLSAG_GGXXG_signature
@ -183,6 +183,21 @@ namespace crypto
END_BOOST_SERIALIZATION()
};
struct generic_double_schnorr_sig_s : public generic_double_schnorr_sig
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD(y0)
FIELD(y1)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE(y0)
BOOST_SERIALIZE(y1)
END_BOOST_SERIALIZATION()
};
struct BGE_proof_s : public BGE_proof
{
BEGIN_SERIALIZE_OBJECT()

View file

@ -21,8 +21,8 @@ namespace tools
};
#ifndef TESTNET
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2390000.pak", "ffc8d2220a4d8b3fba51073a422cbb6139c60858469ea086623f9d16329eb5b4", 2767268964, 5368627200 };
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2390000.pak", "7e58951bc523eb12e0ec07171bc67b3f96bad4d5454dd2da56f642a872e230d3", 3618283035, 5156397056 };
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2500000.pak", "8ffa2cb4213f4f96f97033c65a9e52bc350f683237808597784e79b24d5bfee7", 3242348793, 5905489920 };
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2500000.pak", "5509650e12c8f901e6731a2bfaf3abfd64409e3e1366d3d94cd11db8beddb0c3", 4239505801, 5893566464 };
#else
static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 };
static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 };
@ -50,6 +50,7 @@ namespace tools
boost::system::error_code ec;
uint64_t sz = boost::filesystem::file_size(db_main_file_path, ec);
if (ec) sz = 0;
bool flag_force_predownload = command_line::has_arg(vm, command_line::arg_force_predownload);
if (pre_download.unpacked_size == 0 || !(ec || (pre_download.unpacked_size > sz && pre_download.unpacked_size - sz > pre_download_min_size_difference) || flag_force_predownload) )
{
@ -59,53 +60,59 @@ namespace tools
// okay, let's download
std::string downloading_file_path = db_main_file_path + ".download";
LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0);
epee::net_utils::http::interruptible_http_client cl;
crypto::stream_cn_hash hash_stream;
auto last_update = std::chrono::system_clock::now();
auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes)
if (!command_line::has_arg(vm, command_line::arg_process_predownload_from_path))
{
if (cb_should_stop(total_bytes, received_bytes))
LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0);
epee::net_utils::http::interruptible_http_client cl;
crypto::stream_cn_hash hash_stream;
auto last_update = std::chrono::system_clock::now();
auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes)
{
LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0);
return false;
if (cb_should_stop(total_bytes, received_bytes))
{
LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0);
return false;
}
hash_stream.update(buff.data(), buff.size());
auto dif = std::chrono::system_clock::now() - last_update;
if (dif >= std::chrono::milliseconds(300))
{
boost::io::ios_flags_saver ifs(std::cout);
std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r";
last_update = std::chrono::system_clock::now();
}
return true;
};
tools::create_directories_if_necessary(working_folder);
r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */);
if (!r)
{
LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0);
return !flag_force_predownload; // fatal error only if force-predownload
}
hash_stream.update(buff.data(), buff.size());
auto dif = std::chrono::system_clock::now() - last_update;
if (dif >= std::chrono::milliseconds(300))
crypto::hash data_hash = hash_stream.calculate_hash();
if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash)
{
boost::io::ios_flags_saver ifs(std::cout);
std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r";
last_update = std::chrono::system_clock::now();
LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash);
return !flag_force_predownload; // fatal error only if force-predownload
}
return true;
};
tools::create_directories_if_necessary(working_folder);
r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */);
if (!r)
{
LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0);
return !flag_force_predownload; // fatal error only if force-predownload
LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct", LOG_LEVEL_0);
}
crypto::hash data_hash = hash_stream.calculate_hash();
if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash)
else
{
LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash);
return !flag_force_predownload; // fatal error only if force-predownload
downloading_file_path = command_line::get_arg(vm, command_line::arg_process_predownload_from_path);
}
LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct" , LOG_LEVEL_0);
if (!command_line::has_arg(vm, command_line::arg_validate_predownload))
{
boost::filesystem::remove(db_main_file_path, ec);
@ -138,11 +145,14 @@ namespace tools
std::string path_to_temp_blockchain_file = path_to_temp_blockchain + "/" + dbbs.get_db_main_file_name();
tools::create_directories_if_necessary(path_to_temp_blockchain);
boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec);
if (ec)
if (downloading_file_path != path_to_temp_blockchain_file)
{
LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file);
return false;
boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec);
if (ec)
{
LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file);
return false;
}
}
// remove old blockchain database from disk
@ -180,6 +190,28 @@ namespace tools
r = target_core.init(target_core_vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to init target core");
if (true/*TODO: copnfigure with command line option*/)
{
//set checkpoints
{
currency::checkpoints checkpoints;
bool res = currency::create_checkpoints(checkpoints);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints");
res = source_core.set_checkpoints(std::move(checkpoints));
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
}
{
currency::checkpoints checkpoints;
bool res = currency::create_checkpoints(checkpoints);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints");
res = target_core.set_checkpoints(std::move(checkpoints));
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
}
}
CHECK_AND_ASSERT_MES(target_core.get_top_block_height() == 0, false, "Target blockchain initialized not empty");
uint64_t total_blocks = source_core.get_current_blockchain_size();

View file

@ -411,7 +411,8 @@ bool generate_genesis(const std::string& path_config, uint64_t premine_split_amo
std::cout << ENDL << "PROOF PHRASE: " << gcp.proof_string << ENDL;
uint64_t block_reward_without_fee = 0;
construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations);
uint64_t block_reward = 0;
construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations);
currency::blobdata txb = tx_to_blob(bl.miner_tx);
//self validate block

View file

@ -1166,6 +1166,11 @@ namespace crypto
return scalar_t(crypto::cn_fast_hash(str.c_str(), str.size())); // will reduce mod L
}
static hash h(const std::string& str)
{
return crypto::cn_fast_hash(str.c_str(), str.size());
}
struct hs_t
{
hs_t(size_t size_to_reserve = 0)

View file

@ -8,7 +8,9 @@
#include <string.h>
#include "hash-ops.h"
#ifdef _M_ARM64
#include "malloc.h"
#endif
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
assert(count > 0);
if (count == 1) {

View file

@ -1,5 +1,5 @@
// Copyright (c) 2022-2023 Zano Project
// Copyright (c) 2022-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@ -84,46 +84,47 @@ namespace crypto
scalar_t y;
};
template<generator_tag gen>
template<typename generator_t>
inline bool generate_schnorr_sig_custom_generator(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result, const generator_t& g_point_g)
{
#ifndef NDEBUG
if (A != secret_a * g_point_g)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * g_point_g;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
}
template<generator_tag gen = gt_G>
inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result);
template<>
inline bool generate_schnorr_sig<gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_G)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * c_point_G;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_G);
}
template<>
inline bool generate_schnorr_sig<gt_X>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_X)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * c_point_X;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_X);
}
template<generator_tag gen>
inline bool generate_schnorr_sig(const hash& m, const public_key& A, const secret_key& secret_a, generic_schnorr_sig& result)
{
return generate_schnorr_sig(m, point_t(A), scalar_t(secret_a), result);
}
template<generator_tag gen = gt_G>
inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept;
// TODO @#@# make optimized version inline bool verify_schnorr_sig(const hash& m, const point_t& A, const generic_schnorr_sig& sig) noexcept;
@ -167,6 +168,110 @@ namespace crypto
}
}
// --------------------------------------------
// multi-base Schnorr-like proof (two generators, two secrets, one Fiat-Shamir challenge)
struct generic_double_schnorr_sig
{
scalar_t c;
scalar_t y0;
scalar_t y1;
};
template<generator_tag gen0, generator_tag gen1>
inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result);
template<>
inline bool generate_double_schnorr_sig<gt_G, gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_G || B != secret_b * c_point_G)
return false;
#endif
scalar_t r0 = scalar_t::random();
scalar_t r1 = scalar_t::random();
point_t R0 = r0 * c_point_G;
point_t R1 = r1 * c_point_G;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(B);
hsc.add_point(R0);
hsc.add_point(R1);
result.c = hsc.calc_hash();
result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a
result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b
return true;
}
template<>
inline bool generate_double_schnorr_sig<gt_X, gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_X || B != secret_b * c_point_G)
return false;
#endif
scalar_t r0 = scalar_t::random();
scalar_t r1 = scalar_t::random();
point_t R0 = r0 * c_point_X;
point_t R1 = r1 * c_point_G;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(B);
hsc.add_point(R0);
hsc.add_point(R1);
result.c = hsc.calc_hash();
result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a
result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b
return true;
}
template<generator_tag gen0, generator_tag gen1>
inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept;
template<>
inline bool verify_double_schnorr_sig<gt_G, gt_G>(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced())
return false;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_pub_key(B);
hsc.add_point(A.mul_plus_G(sig.c, sig.y0)); // sig.y0 * G + sig.c * A
hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
template<>
inline bool verify_double_schnorr_sig<gt_X, gt_G>(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced())
return false;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_pub_key(B);
hsc.add_point(sig.y0 * c_point_X + sig.c * A);
hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
// TODO: improve this proof using random weightning factor
struct vector_UG_aggregation_proof
@ -187,4 +292,4 @@ namespace crypto
const vector_UG_aggregation_proof& sig, uint8_t* p_err = nullptr) noexcept;
} // namespace crypto
} // namespace crypto

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -8,14 +8,54 @@
namespace bc_services
{
template<typename T>
struct is_boost_variant : std::false_type {};
template<typename... Args>
struct is_boost_variant<boost::variant<Args...>> : std::true_type {};
template<bool is_variant>
struct type_selector;
template<>
struct type_selector<true>
{
template<typename t_type>
static const std::type_info& get_type(const t_type& t)
{
return t.type();
}
template<typename t_type, typename t_return_type>
static const t_return_type& get(const t_type& t)
{
return boost::get<t_return_type>(t);
}
};
template<>
struct type_selector<false>
{
template<typename t_type>
static const std::type_info& get_type(const t_type& t)
{
return typeid(t);
}
template<typename t_type, typename t_return_type>
static const t_return_type& get(const t_type& t)
{
return t;
}
};
template<class t_attachment_type_container_t>
bool get_first_service_attachment_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, currency::tx_service_attachment& res)
{
for (const auto& item : tx_items)
{
if (item.type() == typeid(currency::tx_service_attachment))
typedef type_selector<is_boost_variant<typename t_attachment_type_container_t::value_type>::value> TS;
if (TS::get_type(item) == typeid(currency::tx_service_attachment))
{
const currency::tx_service_attachment& tsa = boost::get<currency::tx_service_attachment>(item);
const currency::tx_service_attachment& tsa = TS::template get<decltype(item), currency::tx_service_attachment>(item);
if (tsa.service_id == id && tsa.instruction == instruction)
{
res = tsa;
@ -25,4 +65,5 @@ namespace bc_services
}
return false;
}
}
}

View file

@ -3161,7 +3161,7 @@ bool blockchain_storage::get_pos_votes(uint64_t start_index, uint64_t end_index,
summary[v.first].no++;
}
}
for (const auto s_entry : summary)
for (const auto& s_entry : summary)
{
r.votes.push_back(s_entry.second);
r.votes.back().proposal_id = s_entry.first;
@ -3828,14 +3828,7 @@ bool blockchain_storage::unprocess_blockchain_tx_extra(const transaction& tx)
if (ei.m_asset_operation.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED)
{
crypto::public_key asset_id = currency::null_pkey;
if (ei.m_asset_operation.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
calculate_asset_id(ei.m_asset_operation.descriptor.owner, nullptr, &asset_id);
}
else
{
CHECK_AND_NO_ASSERT_MES(false, false, "asset operation not implemented");
}
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ei.m_asset_operation, nullptr, &asset_id), false, "get_or_calculate_asset_id failed");
r = pop_asset_info(asset_id);
CHECK_AND_ASSERT_MES(r, false, "failed to pop_alias_info");
}
@ -4086,15 +4079,14 @@ bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id)
//------------------------------------------------------------------
bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& avc)
{
// asset_id = AUTO_VAL_INIT(asset_id);
// CHECK_AND_ASSERT_MES(validate_asset_operation_balance_proof(tx, tx_id, ado, asset_id), false, "asset operation validation failed!");
CHECK_AND_ASSERT_MES(avc.ado.opt_proof.has_value(), false, "Ownership validation failed - missing signature");
asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop);
bool r = get_type_in_variant_container(avc.tx.proofs, aoop);
CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed - missing signature (asset_operation_ownership_proof)");
CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has invalid history size() == 0");
crypto::public_key owner_key = avc.asset_op_history->back().descriptor.owner;
return crypto::check_signature(get_signature_hash_for_asset_operation(avc.ado), owner_key, *avc.ado.opt_proof);
return crypto::verify_schnorr_sig(avc.tx_id, owner_key, aoop.gss);
}
//------------------------------------------------------------------
bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado)
@ -4105,12 +4097,13 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
calculate_asset_id(avc.ado.descriptor.owner, &avc.asset_id_pt, &avc.asset_id);
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed");
avc.asset_op_history = m_db_assets.find(avc.asset_id);
CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << avc.asset_id << " has already been registered");
avc.amount_to_validate = ado.descriptor.current_supply;
CHECK_AND_ASSERT_MES(validate_asset_operation_amount_proof(avc), false, "asset operation validation failed!");
CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "asset operation validation failed!");
assets_container::t_value_type local_asset_history = AUTO_VAL_INIT(local_asset_history);
local_asset_history.push_back(ado);
@ -4119,14 +4112,12 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has
}
else
{
CHECK_AND_ASSERT_MES(avc.ado.opt_asset_id, false, "asset_id not provided for asset altering operation");
avc.asset_op_history = m_db_assets.find(*avc.ado.opt_asset_id);
avc.asset_id = *avc.ado.opt_asset_id; // consider redisign
avc.asset_id_pt.from_public_key(avc.asset_id);
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed");
avc.asset_op_history = m_db_assets.find(avc.asset_id);
CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << avc.asset_id << " has not been registered");
// check ownership permission
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE /*|| ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN*/)
{
bool r = validate_ado_ownership(avc);
CHECK_AND_ASSERT_MES(r, false, "Faild to validate ownership of asset_descriptor_operation, rejecting");
@ -4157,19 +4148,19 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has
}
else
{
LOG_ERROR("Unknown operation type: " << ado.operation_type);
LOG_ERROR("Unknown operation type: " << (int)ado.operation_type);
return false;
}
if (need_to_validate_balance_proof)
{
bool r = validate_asset_operation_amount_proof(avc);
bool r = validate_asset_operation_amount_commitment(avc);
CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation");
}
assets_container::t_value_type local_asset_history = *avc.asset_op_history;
local_asset_history.push_back(ado);
m_db_assets.set(*avc.ado.opt_asset_id, local_asset_history);
m_db_assets.set(avc.asset_id, local_asset_history);
switch(ado.operation_type)
{
@ -4183,7 +4174,7 @@ bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::has
LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1);
break;
default:
LOG_ERROR("Unknown operation type: " << ado.operation_type);
LOG_ERROR("Unknown operation type: " << (int)ado.operation_type);
}
}
@ -5816,7 +5807,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
};
//inputs
for (const auto in : tx.vin)
for (const auto& in : tx.vin)
{
if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(in))
return false;
@ -5830,7 +5821,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
return false;
}
//outputs
for (const auto out : tx.vout)
for (const auto& out : tx.vout)
{
if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(out))
return false;
@ -5846,7 +5837,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
size_t count_ado = 0;
//extra
for (const auto el : tx.extra)
for (const auto& el : tx.extra)
{
if (el.type() == typeid(asset_descriptor_operation))
count_ado++;
@ -5861,7 +5852,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
}
//attachments
for (const auto el : tx.attachment)
for (const auto& el : tx.attachment)
{
if (!var_is_after_hardfork_2_zone && !is_allowed_before_hardfork2(el))
return false;

View file

@ -27,7 +27,6 @@ namespace currency
ADD_CHECKPOINT(1161000, "96990d851b484e30190678756ba2a4d3a2f92b987e2470728ac1e38b2bf35908");
ADD_CHECKPOINT(1480000, "5dd3381eec35e8b4eba4518bfd8eec682a4292761d92218fd59b9f0ffedad3fe");
ADD_CHECKPOINT(2000000, "7b6698a8cc279aa78d6263f01fef186bd16f5b1ea263a7f4714abc1d506b9cb3");
ADD_CHECKPOINT(2390000, "10797d34349d0ef1d1ab4b41ada6f8f2c2f86a7f7eebe44dd2ba06067cb47e0a");
#endif
return true;

View file

@ -438,18 +438,21 @@ namespace currency
END_BOOST_SERIALIZATION()
};
// 1) for txs without ZC inputs: proves that balance point = lin(G) (cancels out G component of outputs' amount commitments, asset tags assumed to be H (native coin) and non-blinded)
// 2) for txs with ZC inputs: proves that balance point = lin(X) (cancels out X component of blinded asset tags within amount commitments for both outputs and inputs (pseudo outs))
// First part of a double Schnorr proof:
// 1) for txs without ZC inputs: proves that balance point = lin(G) (cancels out G component of outputs' amount commitments, asset tags assumed to be H (native coin) and non-blinded)
// 2) for txs with ZC inputs: proves that balance point = lin(X) (cancels out X component of blinded asset tags within amount commitments for both outputs and inputs (pseudo outs))
// Second part:
// proof of knowing transaction secret key (with respect to G)
struct zc_balance_proof
{
crypto::generic_schnorr_sig_s ss;
crypto::generic_double_schnorr_sig_s dss;
BEGIN_SERIALIZE_OBJECT()
FIELD(ss)
FIELD(dss)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(ss)
BOOST_SERIALIZE(dss)
END_BOOST_SERIALIZATION()
};
@ -772,7 +775,6 @@ namespace currency
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
asset_descriptor_base descriptor;
crypto::public_key amount_commitment; // premultiplied by 1/8
boost::optional<crypto::signature> opt_proof; // operation proof - for update/emit
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER;
@ -781,7 +783,6 @@ namespace currency
FIELD(descriptor)
FIELD(amount_commitment)
END_VERSION_UNDER(1)
FIELD(opt_proof)
FIELD(opt_asset_id)
END_SERIALIZE()
@ -790,7 +791,6 @@ namespace currency
BOOST_SERIALIZE(descriptor)
BOOST_SERIALIZE(amount_commitment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(opt_proof)
BOOST_SERIALIZE(opt_asset_id)
END_BOOST_SERIALIZATION()
};
@ -816,6 +816,21 @@ namespace currency
};
struct asset_operation_ownership_proof
{
crypto::generic_schnorr_sig_s gss;
uint8_t version = 0;
BEGIN_VERSIONED_SERIALIZE(0, version)
FIELD(gss)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(gss)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(version)
END_BOOST_SERIALIZATION()
};
struct extra_padding
@ -921,7 +936,7 @@ namespace currency
typedef boost::variant<NLSAG_sig, void_sig, ZC_sig, zarcanum_sig> signature_v;
typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof> proof_v;
typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof, asset_operation_ownership_proof> proof_v;
//include backward compatibility defintions
@ -1108,6 +1123,7 @@ BLOB_SERIALIZER(currency::txout_to_key);
BOOST_CLASS_VERSION(currency::asset_descriptor_operation, 1);
BOOST_CLASS_VERSION(currency::asset_operation_proof, 1);
BOOST_CLASS_VERSION(currency::asset_operation_ownership_proof, 1);
// txin_v variant currency
@ -1178,6 +1194,7 @@ SET_VARIANT_TAGS(currency::zc_balance_proof, 48, "zc_balance_proof");
SET_VARIANT_TAGS(currency::asset_descriptor_operation, 49, "asset_descriptor_base");
SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof");
SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation_ownership_proof");

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -10,7 +10,7 @@
#ifndef TESTNET
#define CURRENCY_FORMATION_VERSION 84
#else
#define CURRENCY_FORMATION_VERSION 94
#define CURRENCY_FORMATION_VERSION 97
#endif
#define CURRENCY_GENESIS_NONCE (CURRENCY_FORMATION_VERSION + 101011010121) //bender's nightmare
@ -227,7 +227,7 @@
#define CURRENCY_POOLDATA_FOLDERNAME_PREFIX "poolstate_"
#define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX "blockchain_"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v1"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v2"
#define P2P_NET_DATA_FILENAME "p2pstate.bin"
#define MINER_CONFIG_FILENAME "miner_conf.json"
@ -250,8 +250,8 @@
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
#ifndef TESTNET
#define WALLET_FILE_SERIALIZATION_VERSION 161
#define WALLET_FILE_LAST_SUPPORTED_VERSION 161
#define WALLET_FILE_SERIALIZATION_VERSION 162
#define WALLET_FILE_LAST_SUPPORTED_VERSION 162
#else
#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+76)
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+76)
@ -264,10 +264,10 @@
#define BLOCK_MINOR_VERSION_GENESIS 0
#define BLOCK_MAJOR_VERSION_INITIAL 0
#ifndef TESTNET
#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624
#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577
#define ZANO_HARDFORK_04_AFTER_HEIGHT 999999999
#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624 // 2019-09-21 20:25:16
#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999 // 2021-04-05 09:11:45
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 // 2021-06-01 23:28:10
#define ZANO_HARDFORK_04_AFTER_HEIGHT 2555000 // 2024-03-21 10:16:46 (expected)
#else
/////// Zarcanum Testnet //////////////////////////////
#define ZANO_HARDFORK_01_AFTER_HEIGHT 0

View file

@ -76,7 +76,10 @@ namespace currency
bool core::handle_command_line(const boost::program_options::variables_map& vm)
{
m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir);
m_stop_after_height = static_cast<uint64_t>(command_line::get_arg(vm, command_line::arg_stop_after_height));
m_stop_after_height = 0;
if(command_line::has_arg(vm, command_line::arg_stop_after_height))
m_stop_after_height = static_cast<uint64_t>(command_line::get_arg(vm, command_line::arg_stop_after_height));
if (m_stop_after_height != 0)
{
LOG_PRINT_YELLOW("Daemon will STOP after block " << m_stop_after_height, LOG_LEVEL_0);

View file

@ -171,8 +171,8 @@ namespace currency
asset_descriptor_operation ado{};
if (is_asset_emitting_transaction(tx, &ado))
{
crypto::point_t asset_id_pt = crypto::c_point_0;
calculate_asset_id(ado.descriptor.owner, &asset_id_pt, nullptr); // TODO @#@# optimization: this expensive calculation should be done only once
crypto::point_t asset_id_pt{};
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &asset_id_pt, nullptr), false, "get_or_calculate_asset_id failed"); // TODO @#@# expensive operation, consider caching
pseudo_outs_blinded_asset_ids.emplace_back(asset_id_pt); // additional ring member for asset emitting tx
}
@ -301,8 +301,8 @@ namespace currency
#ifndef NDEBUG
CHECK_AND_ASSERT_MES(commitment_to_zero == secret_x * crypto::c_point_G, false, "internal error: commitment_to_zero is malformed (G)");
#endif
r = crypto::generate_schnorr_sig<crypto::gt_G>(tx_id, commitment_to_zero, secret_x, proof.ss);
CHECK_AND_ASSERT_MES(r, false, "generate_schnorr_sig (G) failed");
r = crypto::generate_double_schnorr_sig<crypto::gt_G, crypto::gt_G>(tx_id, commitment_to_zero, secret_x, ogc.tx_pub_key_p, ogc.tx_key.sec, proof.dss);
CHECK_AND_ASSERT_MES(r, false, "generate_double_schnorr_sig (G, G) failed");
}
else // i.e. zc_inputs_count != 0
{
@ -326,8 +326,8 @@ namespace currency
bool commitment_to_zero_is_sane = commitment_to_zero == secret_x * crypto::c_point_X;
CHECK_AND_ASSERT_MES(commitment_to_zero_is_sane, false, "internal error: commitment_to_zero is malformed (X)");
#endif
r = crypto::generate_schnorr_sig<crypto::gt_X>(tx_id, commitment_to_zero, secret_x, proof.ss);
CHECK_AND_ASSERT_MES(r, false, "generate_schnorr_sig (X) failed");
r = crypto::generate_double_schnorr_sig<crypto::gt_X, crypto::gt_G>(tx_id, commitment_to_zero, secret_x, ogc.tx_pub_key_p, ogc.tx_key.sec, proof.dss);
CHECK_AND_ASSERT_MES(r, false, "genergenerate_double_schnorr_sigate_schnorr_sig (X, G) failed");
}
return true;
@ -447,11 +447,9 @@ namespace currency
tx = AUTO_VAL_INIT_T(transaction);
tx.version = tx_version;
keypair txkey_local{};
if (!tx_one_time_key_to_use)
txkey_local = keypair::generate();
const keypair& txkey = tx_one_time_key_to_use ? *tx_one_time_key_to_use : txkey_local;
add_tx_pub_key_to_extra(tx, txkey.pub);
tx_generation_context tx_gen_context{};
tx_gen_context.set_tx_key(tx_one_time_key_to_use ? *tx_one_time_key_to_use : keypair::generate());
add_tx_pub_key_to_extra(tx, tx_gen_context.tx_key.pub);
if (extra_nonce.size())
if (!add_tx_extra_userdata(tx, extra_nonce))
return false;
@ -488,7 +486,6 @@ namespace currency
}
// fill outputs
tx_generation_context tx_gen_context{};
tx_gen_context.resize(zc_ins_count, destinations.size()); // auxiliary data for each output
uint64_t output_index = 0;
std::set<uint16_t> deriv_cache;
@ -496,7 +493,7 @@ namespace currency
{
finalized_tx result = AUTO_VAL_INIT(result);
uint8_t tx_outs_attr = 0;
r = construct_tx_out(d, txkey.sec, output_index, tx, deriv_cache, account_keys(),
r = construct_tx_out(d, tx_gen_context.tx_key.sec, output_index, tx, deriv_cache, account_keys(),
tx_gen_context.asset_id_blinding_masks[output_index], tx_gen_context.amount_blinding_masks[output_index],
tx_gen_context.blinded_asset_ids[output_index], tx_gen_context.amount_commitments[output_index], result, tx_outs_attr);
CHECK_AND_ASSERT_MES(r, false, "construct_tx_out failed, output #" << output_index << ", amount: " << print_money_brief(d.amount));
@ -576,7 +573,7 @@ namespace currency
return true;
}
//-----------------------------------------------------------------------------------------------
bool validate_asset_operation_amount_proof(asset_op_verification_context& context)// const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado, crypto::public_key& asset_id)
bool validate_asset_operation_amount_commitment(asset_op_verification_context& context)
{
CHECK_AND_ASSERT_MES(count_type_in_variant_container<asset_operation_proof>(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<const asset_operation_proof>(context.tx.proofs);
@ -608,6 +605,8 @@ namespace currency
bool r = get_type_in_variant_container<zc_balance_proof>(tx.proofs, balance_proof);
CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof is missing in tx proofs");
crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
size_t zc_inputs_count = 0;
uint64_t bare_inputs_sum = additional_inputs_amount_and_fees_for_mining_tx;
for(auto& vin : tx.vin)
@ -645,7 +644,7 @@ namespace currency
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
{
// opt_amount_commitment supposed to be validated earlier in validate_asset_operation()
// amount_commitment supposed to be validated earlier in validate_asset_operation_amount_commitment()
sum_of_pseudo_out_amount_commitments += crypto::point_t(ado.amount_commitment); // *1/8
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
@ -675,13 +674,13 @@ namespace currency
CHECK_AND_ASSERT_MES(zc_inputs_count == zc_sigs_count, false, "zc inputs count (" << zc_inputs_count << ") and zc sigs count (" << zc_sigs_count << ") missmatch");
if (zc_inputs_count > 0)
{
r = crypto::verify_schnorr_sig<crypto::gt_X>(tx_id, commitment_to_zero.to_public_key(), balance_proof.ss);
CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof (X) is invalid");
r = crypto::verify_double_schnorr_sig<crypto::gt_X, crypto::gt_G>(tx_id, commitment_to_zero, tx_pub_key, balance_proof.dss);
CHECK_AND_ASSERT_MES(r, false, "verify_double_schnorr_sig (X, G) is invalid");
}
else
{
r = crypto::verify_schnorr_sig<crypto::gt_G>(tx_id, commitment_to_zero.to_public_key(), balance_proof.ss);
CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof (G) is invalid");
r = crypto::verify_double_schnorr_sig<crypto::gt_G, crypto::gt_G>(tx_id, commitment_to_zero, tx_pub_key, balance_proof.dss);
CHECK_AND_ASSERT_MES(r, false, "verify_double_schnorr_sig (G, G) is invalid");
}
return true;
}
@ -1138,20 +1137,21 @@ namespace currency
return origin_blob;
}
//---------------------------------------------------------------
bool validate_ado_update_allowed(const asset_descriptor_base& a, const asset_descriptor_base& b)
bool validate_ado_update_allowed(const asset_descriptor_base& new_ado, const asset_descriptor_base& prev_ado)
{
if (a.total_max_supply != b.total_max_supply) return false;
//if (a.current_supply != b.current_supply) return false;
if (a.decimal_point != b.decimal_point) return false;
if (a.ticker != b.ticker) return false;
if (a.full_name != b.full_name) return false;
if (new_ado.total_max_supply != prev_ado.total_max_supply) return false;
if (new_ado.current_supply > prev_ado.total_max_supply) return false;
if (new_ado.decimal_point != prev_ado.decimal_point) return false;
if (new_ado.ticker != prev_ado.ticker) return false;
if (new_ado.full_name != prev_ado.full_name) return false;
//a.meta_info;
if (a.owner != b.owner) return false;
if (a.hidden_supply != b.hidden_supply) return false;
//if (a.owner != b.owner) return false;
if (new_ado.hidden_supply != prev_ado.hidden_supply) return false;
return true;
}
//---------------------------------------------------------------
/*
crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado)
{
asset_descriptor_operation ado_local = ado;
@ -1165,6 +1165,7 @@ namespace currency
{
op.opt_proof = boost::none;
}
*/
//---------------------------------------------------------------
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr /* = CURRENCY_TO_KEY_OUT_RELAXED */)
@ -2111,20 +2112,45 @@ namespace currency
}
#define CRYPTO_HASH_ASSET_ID_ITERATIONS 1024
void calculate_asset_id(const crypto::public_key& asset_owner, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key)
bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key)
{
crypto::hash h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, asset_owner);
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT ||
ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE ||
ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN )
{
CHECK_AND_ASSERT_MES(ado.opt_asset_id.has_value(), false, "ado.opt_asset_id has no value, op: " << (int)ado.operation_type << ", " << get_asset_operation_type_string(ado.operation_type));
//LOG_PRINT_YELLOW("ado.opt_asset_id = " << ado.opt_asset_id.get(), LOG_LEVEL_0);
if (p_result_pub_key)
*p_result_pub_key = ado.opt_asset_id.get();
if (p_result_point)
*p_result_point = crypto::point_t(ado.opt_asset_id.get());
return true;
}
// otherwise, calculate asset id
crypto::hash_helper_t::hs_t hsc;
hsc.add_32_chars(CRYPTO_HDS_ASSET_ID);
hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.ticker));
hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.full_name));
hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.meta_info));
hsc.add_scalar(crypto::scalar_t(ado.descriptor.total_max_supply));
hsc.add_scalar(crypto::scalar_t(ado.descriptor.decimal_point));
hsc.add_pub_key(ado.descriptor.owner);
crypto::hash h = hsc.calc_hash_no_reduce();
// this hash function needs to be computationally expensive (s.a. the whitepaper)
for(uint64_t i = 0; i < CRYPTO_HASH_ASSET_ID_ITERATIONS; ++i)
h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, h, i);
crypto::point_t local_point{};
if (!p_result_point)
p_result_point = &local_point;
*p_result_point = crypto::hash_helper_t::hp(&h, sizeof h);
crypto::point_t result = crypto::hash_helper_t::hp(&h, sizeof h);
if (p_result_point)
*p_result_point = result;
if (p_result_pub_key)
p_result_point->to_public_key(*p_result_pub_key);
result.to_public_key(*p_result_pub_key);
//LOG_PRINT_YELLOW("calculated asset_id = " << result, LOG_LEVEL_0);
return true;
}
const asset_descriptor_base& get_native_coin_asset_descriptor()
@ -2155,14 +2181,20 @@ namespace currency
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
crypto::secret_key asset_control_key{};
bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed");
//crypto::secret_key asset_control_key{};
//bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
//CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed");
//
// old:
// asset_control_key = Hs(CRYPTO_HDS_ASSET_CONTROL_KEY, 8 * tx_key.sec * sender_account_keys.account_address.spend_public_key, 0)
// ado.descriptor.owner = asset_control_key * G
ado.descriptor.owner = sender_account_keys.account_address.spend_public_key;
calculate_asset_id(ado.descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id);
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed");
// calculate amount blinding mask
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, asset_control_key, tx_key.pub);
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec);
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0;
@ -2179,16 +2211,47 @@ namespace currency
gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed");
// calculate amount blinding mask
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec);
gen_context.ao_commitment_in_outputs = true;
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_burned_assets = 0;
for (auto& item : ftp.sources)
{
if (item.asset_id == gen_context.ao_asset_id)
{
amount_of_burned_assets += item.amount;
}
}
for (auto& item : ftp.prepared_destinations)
{
if (item.asset_id == gen_context.ao_asset_id)
{
CHECK_AND_ASSERT_THROW_MES(amount_of_burned_assets >= item.amount, "Failed to find burn amount, failed condition: amount_of_burned_assets(" << amount_of_burned_assets << ") >= item.amount(" << item.amount << ")");
amount_of_burned_assets -= item.amount;
}
}
ado.descriptor.current_supply -= amount_of_burned_assets;
gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_burn{ &ado });
}
else
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
{
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT");
CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed");
gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id);
// calculate amount blinding mask
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key, tx_key.pub);
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec);
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0;
@ -2213,47 +2276,27 @@ namespace currency
//fields that not supposed to be changed?
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN");
gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id);
// calculate amount blinding mask
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key, tx_key.pub);
gen_context.ao_commitment_in_outputs = true;
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_burned_assets = 0;
for (auto& item: ftp.sources)
{
if (item.asset_id == gen_context.ao_asset_id)
{
amount_of_burned_assets += item.amount;
}
}
for (auto& item : ftp.prepared_destinations)
{
if (item.asset_id == gen_context.ao_asset_id )
{
CHECK_AND_ASSERT_THROW_MES(amount_of_burned_assets >= item.amount, "Failed to find burn amount, failed condition: amount_of_burned_assets(" << amount_of_burned_assets << ") >= item.amount("<< item.amount << ")");
amount_of_burned_assets -= item.amount;
}
}
ado.descriptor.current_supply -= amount_of_burned_assets;
gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_seal{ &ado });
ftp.need_to_generate_ado_proof = true;
/*
//seal it with owners signature
crypto::signature sig = currency::null_sig;
crypto::public_key pub_k = currency::null_pkey;
crypto::secret_key_to_public_key(ftp.asset_control_key, pub_k);
crypto::generate_signature(get_signature_hash_for_asset_operation(ado), pub_k, ftp.asset_control_key, sig);
crypto::hash h = get_signature_hash_for_asset_operation(ado);
if (ftp.pthirdparty_sign_handler)
{
bool r = ftp.pthirdparty_sign_handler->sign(h, ftp.ado_current_asset_owner, sig);
CHECK_AND_ASSERT_MES(r, false, "asset thirparty sign failed");
}
else
{
crypto::public_key pub_k = currency::null_pkey;
crypto::secret_key_to_public_key(sender_account_keys.spend_secret_key, pub_k);
CHECK_AND_ASSERT_MES(ftp.ado_current_asset_owner == pub_k, false, "asset owner key not matched with provided private key for asset operation signing");
crypto::generate_signature(h, pub_k, account_keys.spend_secret_key, sig);
}
ado.opt_proof = sig;
*/
}
return true;
}
@ -2438,15 +2481,14 @@ namespace currency
LOG_PRINT_YELLOW("WARNING: tx v1 should not use ZC inputs", LOG_LEVEL_0);
}
tx_generation_context& gen_context = result.ftp.gen_context;
keypair txkey = AUTO_VAL_INIT(txkey);
if (!append_mode)
{
txkey = keypair::generate();
gen_context.set_tx_key(keypair::generate());
//deterministic_generate_tx_onetime_key(key_images_total, sender_account_keys, txkey);
add_tx_pub_key_to_extra(tx, txkey.pub);
one_time_tx_secret_key = txkey.sec;
add_tx_pub_key_to_extra(tx, gen_context.tx_key.pub);
one_time_tx_secret_key = gen_context.tx_key.sec;
//add flags
etc_tx_flags16_t e = AUTO_VAL_INIT(e);
@ -2455,13 +2497,12 @@ namespace currency
//include offers if need
tx.attachment = attachments;
encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, txkey, result.derivation);
encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, gen_context.tx_key, result.derivation);
}
else
{
txkey.pub = get_tx_pub_key_from_extra(tx);
txkey.sec = one_time_tx_secret_key;
CHECK_AND_ASSERT_MES(txkey.pub != null_pkey && txkey.sec != null_skey, false, "In append mode both public and secret keys must be provided");
gen_context.set_tx_key(keypair{get_tx_pub_key_from_extra(tx), one_time_tx_secret_key});
CHECK_AND_ASSERT_MES(gen_context.tx_key.pub != null_pkey && gen_context.tx_key.sec != null_skey, false, "In append mode both public and secret keys must be provided");
//separately encrypt attachments without putting extra
result.derivation = get_encryption_key_derivation(true, tx, sender_account_keys);
@ -2471,7 +2512,7 @@ namespace currency
std::vector<extra_v> extra_local = extra;
std::vector<attachment_v> attachments_local = attachments;
encrypt_attach_visitor v(was_attachment_crypted_entries, derivation, txkey, account_public_address(), sender_account_keys);
encrypt_attach_visitor v(was_attachment_crypted_entries, derivation, gen_context.tx_key, account_public_address(), sender_account_keys);
for (auto& a : attachments_local)
boost::apply_visitor(v, a);
for (auto& a : extra_local)
@ -2481,7 +2522,7 @@ namespace currency
tx.attachment.insert(tx.attachment.end(), attachments_local.begin(), attachments_local.end());
tx.extra.insert(tx.extra.end(), extra_local.begin(), extra_local.end());
for (const auto in : tx.vin)
for (const auto& in : tx.vin)
{
if (in.type() == typeid(txin_zc_input))
{
@ -2499,8 +2540,6 @@ namespace currency
// OUTs
//
std::vector<tx_destination_entry> shuffled_dsts(destinations);
//size_t outputs_to_be_constructed = shuffled_dsts.size();
tx_generation_context& gen_context = result.ftp.gen_context;
gen_context.resize(zc_inputs_count, tx.vout.size() + shuffled_dsts.size());
// ASSET oprations handling
@ -2510,7 +2549,7 @@ namespace currency
pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
if (pado)
{
bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, txkey, shuffled_dsts);
bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, gen_context.tx_key, shuffled_dsts);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct_tx_handle_ado()");
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation{ pado });
}
@ -2533,7 +2572,7 @@ namespace currency
if (!(flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) && all_inputs_are_obviously_native_coins && gen_context.ao_asset_id == currency::null_pkey)
dst_entr.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // all inputs are obviously native coins -- all outputs must have explicit asset ids (unless there's an asset emission)
r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys,
r = construct_tx_out(dst_entr, gen_context.tx_key.sec, output_index, tx, deriv_cache, sender_account_keys,
gen_context.asset_id_blinding_masks[output_index], gen_context.amount_blinding_masks[output_index],
gen_context.blinded_asset_ids[output_index], gen_context.amount_commitments[output_index], result, tx_outs_attr);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct tx out");
@ -2642,7 +2681,7 @@ namespace currency
else
{
// NLSAG
r = generate_NLSAG_sig(tx_hash_for_signature, tx_prefix_hash, i_ + input_starter_index, source_entry, sender_account_keys, in_contexts[i_mapped], txkey, flags, tx, &ss_ring_s);
r = generate_NLSAG_sig(tx_hash_for_signature, tx_prefix_hash, i_ + input_starter_index, source_entry, sender_account_keys, in_contexts[i_mapped], gen_context.tx_key, flags, tx, &ss_ring_s);
CHECK_AND_ASSERT_MES(r, false, "generate_NLSAG_sig failed");
}
@ -2684,6 +2723,25 @@ namespace currency
aop.opt_amount_commitment_g_proof = aop_g_sig;
tx.proofs.emplace_back(std::move(aop));
}
if(ftp.need_to_generate_ado_proof)
{
asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop);
if (ftp.pthirdparty_sign_handler)
{
//ask third party to generate proof
r = ftp.pthirdparty_sign_handler->sign(tx_prefix_hash, ftp.ado_current_asset_owner, aoop.gss);
CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado by thirdparty");
}
else
{
//generate signature by wallet account
r = crypto::generate_schnorr_sig(tx_prefix_hash, ftp.ado_current_asset_owner, sender_account_keys.spend_secret_key, aoop.gss);
CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado proof");
}
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_after_asset_ownership_proof_generated{ &aoop });
tx.proofs.emplace_back(aoop);
}
}
//size_t prefix_size = get_object_blobsize(static_cast<const transaction_prefix&>(tx));
@ -3180,7 +3238,7 @@ namespace currency
if (P_prime.to_public_key() != zo.stealth_address)
return false;
crypto::point_t Q_prime = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * 8 * crypto::point_t(addr.view_public_key); // Q' * 8 =? Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V
crypto::point_t Q_prime = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(addr.view_public_key).modify_mul8(); // Q' * 8 =? Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V
if (Q_prime != crypto::point_t(zo.concealing_point).modify_mul8())
return false;
@ -3319,7 +3377,7 @@ namespace currency
return true;
}
//---------------------------------------------------------------
bool set_payment_id_to_tx(std::vector<attachment_v>& att, const std::string& payment_id)
bool set_payment_id_to_tx(std::vector<attachment_v>& att, const std::string& payment_id, bool is_in_hardfork4)
{
if (!is_payment_id_size_ok(payment_id))
return false;
@ -3327,6 +3385,10 @@ namespace currency
tx_service_attachment tsa = AUTO_VAL_INIT(tsa);
tsa.service_id = BC_PAYMENT_ID_SERVICE_ID;
tsa.body = payment_id;
if (is_in_hardfork4)
{
tsa.flags = TX_SERVICE_ATTACHMENT_ENCRYPT_BODY;
}
att.push_back(tsa);
return true;
}

View file

@ -134,15 +134,18 @@ namespace currency
END_KV_SERIALIZE_MAP()
};
struct htlc_info
{
bool hltc_our_out_is_before_expiration;
};
struct htlc_info
{
bool hltc_our_out_is_before_expiration;
};
struct thirdparty_sign_handler
{
virtual bool sign(const crypto::hash& h, const crypto::public_key& owner_public_key, crypto::generic_schnorr_sig& sig);
};
struct finalize_tx_param
{
uint64_t unlock_time;
std::vector<currency::extra_v> extra;
std::vector<currency::attachment_v> attachments;
@ -158,10 +161,15 @@ namespace currency
crypto::public_key spend_pub_key; // only for validations
uint64_t tx_version;
uint64_t mode_separate_fee = 0;
crypto::secret_key asset_control_key = currency::null_skey;
epee::misc_utils::events_dispatcher* pevents_dispatcher;
tx_generation_context gen_context{}; // solely for consolidated txs
//crypto::secret_key asset_control_key = currency::null_skey;
crypto::public_key ado_current_asset_owner = null_pkey;
thirdparty_sign_handler* pthirdparty_sign_handler = nullptr;
mutable bool need_to_generate_ado_proof = false;
BEGIN_SERIALIZE_OBJECT()
FIELD(unlock_time)
@ -179,9 +187,12 @@ namespace currency
FIELD(spend_pub_key)
FIELD(tx_version)
FIELD(mode_separate_fee)
FIELD(asset_control_key)
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
{
FIELD(gen_context);
}
FIELD(ado_current_asset_owner)
FIELD(need_to_generate_ado_proof)
END_SERIALIZE()
};
@ -264,7 +275,7 @@ namespace currency
const std::vector<tx_out_v>& vouts, zc_outs_range_proof& result);
bool check_tx_bare_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0);
bool check_tx_balance(const transaction& tx, const crypto::hash& tx_id, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0);
bool validate_asset_operation_amount_proof(asset_op_verification_context& context);
bool validate_asset_operation_amount_commitment(asset_op_verification_context& context);
const char* get_asset_operation_type_string(size_t asset_operation_type, bool short_name = false);
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
@ -331,7 +342,7 @@ namespace currency
uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd); // returns tx version based on the height of the block where the transaction is expected to be
bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& param, finalized_tx& result);
void calculate_asset_id(const crypto::public_key& asset_owner, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key);
bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key);
const asset_descriptor_base& get_native_coin_asset_descriptor();
bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed = nullptr);
@ -420,7 +431,7 @@ namespace currency
bool addendum_to_hexstr(const std::vector<crypto::hash>& add, std::string& hex_buff);
bool hexstr_to_addendum(const std::string& hex_buff, std::vector<crypto::hash>& add);
bool set_payment_id_to_tx(std::vector<attachment_v>& att, const std::string& payment_id);
bool set_payment_id_to_tx(std::vector<attachment_v>& att, const std::string& payment_id, bool is_in_hardfork4 = false);
bool add_padding_to_tx(transaction& tx, size_t count);
bool is_service_tx(const transaction& tx);
bool does_tx_have_only_mixin_inputs(const transaction& tx);
@ -661,7 +672,7 @@ namespace currency
}
//---------------------------------------------------------------
template<typename t_container>
bool get_payment_id_from_tx(const t_container& att, std::string& payment_id)
bool get_payment_id_from_decrypted_container(const t_container& att, std::string& payment_id)
{
tx_service_attachment sa = AUTO_VAL_INIT(sa);
if (bc_services::get_first_service_attachment_by_id(att, BC_PAYMENT_ID_SERVICE_ID, "", sa))

View file

@ -398,7 +398,7 @@ namespace currency
CATCH_ENTRY2(std::vector<tx_source_entry::output_entry>{});
}
//---------------------------------------------------------------
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key)
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context)
{
//TODO: Implement this function before mainnet
#ifdef TESTNET

View file

@ -243,6 +243,12 @@ namespace currency
amount_blinding_masks.size() == outs_count;
}
void set_tx_key(const keypair& kp)
{
tx_key = kp;
tx_pub_key_p = crypto::point_t(tx_key.pub);
}
// per output data
std::vector<crypto::point_t> asset_ids;
std::vector<crypto::point_t> blinded_asset_ids; // generate_zc_outs_range_proof
@ -274,6 +280,10 @@ namespace currency
crypto::scalar_t ao_amount_blinding_mask {}; // generate_tx_balance_proof generate_ZC_sig
bool ao_commitment_in_outputs = false;
// per tx data
keypair tx_key {}; //
crypto::point_t tx_pub_key_p = crypto::c_point_0; // == tx_key.pub
// consider redesign, some data may possibly be excluded from kv serialization -- sowle
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_ids)
@ -297,6 +307,8 @@ namespace currency
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_commitment)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_blinding_mask)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_commitment_in_outputs)
KV_SERIALIZE_POD_AS_HEX_STRING(tx_key)
KV_SERIALIZE_POD_AS_HEX_STRING(tx_pub_key_p)
END_KV_SERIALIZE_MAP()
// solely for consolidated txs, asset opration fields are not serialized
@ -325,10 +337,14 @@ namespace currency
//ao_amount_commitment
//ao_amount_blinding_mask
//ao_commitment_in_outputs
FIELD(tx_key.pub) // TODO: change to sane serialization FIELD(tx_key)
FIELD(tx_key.sec)
FIELD(tx_pub_key_p)
END_SERIALIZE()
}; // struct tx_generation_context
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key);
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context);
std::string transform_tx_to_str(const transaction& tx);
transaction transform_str_to_tx(const std::string& tx_str);

View file

@ -162,6 +162,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, command_line::arg_no_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_force_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_process_predownload_from_path);
command_line::add_arg(desc_cmd_sett, command_line::arg_validate_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_predownload_link);
command_line::add_arg(desc_cmd_sett, command_line::arg_disable_ntp);

@ -1 +1 @@
Subproject commit 18cb69f348bae38186f3a8da8bc9fc9991d38cd1
Subproject commit f040b10090a0246ee5f68a37bb4fcc13e6abebcc

View file

@ -118,10 +118,9 @@ namespace currency
res.minimum_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_pool_min_fee;
auto & hf = m_core.get_blockchain_storage().get_core_runtime_config().hard_forks.m_height_the_hardfork_n_active_after;
res.is_hardfok_active.resize(hf.size());
for (size_t i = 0; i != hf.size(); i++)
{
res.is_hardfok_active[i] = m_core.get_blockchain_storage().is_hardfork_active(i);
res.is_hardfok_active.push_back(m_core.get_blockchain_storage().is_hardfork_active(i));
}
//conditional values
@ -680,7 +679,7 @@ namespace currency
{
std::list<currency::extra_alias_entry> al_list;
m_core.get_tx_pool().get_aliases_from_tx_pool(al_list);
for (const auto a : al_list)
for (const auto& a : al_list)
{
res.aliases_que.push_back(alias_info_to_rpc_alias_info(a));
}

View file

@ -793,7 +793,7 @@ namespace currency
uint64_t minimum_fee;
uint64_t last_block_timestamp;
std::string last_block_hash;
std::vector<bool> is_hardfok_active;
std::list<bool> is_hardfok_active;
//market
uint64_t offers_count;

View file

@ -1681,7 +1681,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
std::vector<currency::attachment_v> attachments;
if (!payment_id.empty() && !set_payment_id_to_tx(attachments, payment_id))
if (!payment_id.empty() && !set_payment_id_to_tx(attachments, payment_id, m_wallet->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)))
{
fail_msg_writer() << "provided (or embedded) payment id can't be set: \"" << payment_id << "\"";
return true;

View file

@ -8,6 +8,6 @@
#define PROJECT_REVISION "0"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 253
#define PROJECT_VERSION_BUILD_NO 265
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -400,30 +400,18 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
{
do
{
crypto::public_key asset_id{};
if (ado.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED)
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(get_or_calculate_asset_id(ado, nullptr, &asset_id), "get_or_calculate_asset_id failed");
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
crypto::public_key self_check = AUTO_VAL_INIT(self_check);
crypto::secret_key asset_control_key = AUTO_VAL_INIT(asset_control_key);
bool r = derive_key_pair_from_key_pair(ptc.tx_pub_key, m_account.get_keys().spend_secret_key, asset_control_key, self_check, CRYPTO_HDS_ASSET_CONTROL_KEY);
if (!r)
{
//not critical error, continue to work
LOG_ERROR("Failed to derive_key_pair_from_key_pair for asset_descriptor_operation in tx " << ptc.tx_hash());
if (ado.descriptor.owner != m_account.get_public_address().spend_public_key)
break;
}
if (self_check != ado.descriptor.owner)
{
//still not critical error
LOG_ERROR("Public key from asset_descriptor_operation(" << ado.descriptor.owner << ") not much with derived public key(" << self_check << "), for tx" << ptc.tx_hash());
break;
}
crypto::public_key asset_id{};
calculate_asset_id(ado.descriptor.owner, nullptr, &asset_id);
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(m_own_asset_descriptors.count(asset_id) == 0, "asset with asset_id " << asset_id << " has already been registered in the wallet as own asset");
wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id];
asset_context.asset_descriptor = ado.descriptor;
asset_context.control_key = asset_control_key;
std::stringstream ss;
ss << "New Asset Registered:"
@ -440,22 +428,78 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(ado.opt_asset_id, get_asset_operation_type_string(ado.operation_type) << " failed with empty opt_asset_id");
auto it = m_own_asset_descriptors.find(*ado.opt_asset_id);
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(it != m_own_asset_descriptors.end(), "asset with asset_id " << *ado.opt_asset_id << " not found during " << get_asset_operation_type_string(ado.operation_type));
if (it->second.asset_descriptor.owner != ado.descriptor.owner)
auto it = m_own_asset_descriptors.find(asset_id);
if (it == m_own_asset_descriptors.end())
break;
//asset had been updated
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE )
{
auto it = m_own_asset_descriptors.find(asset_id);
if (it == m_own_asset_descriptors.end())
{
//ownership of the asset had been transfered
add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second });
m_own_asset_descriptors.erase(it);
if (ado.descriptor.owner == m_account.get_public_address().spend_public_key)
{
// ownership of the asset acquired
wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id];
asset_context.asset_descriptor = ado.descriptor;
std::stringstream ss;
ss << "Asset ownership acquired:"
<< ENDL << "asset id: " << asset_id
<< ENDL << "Name: " << ado.descriptor.full_name
<< ENDL << "Ticker: " << ado.descriptor.ticker
<< ENDL << "Total Max Supply: " << print_asset_money(ado.descriptor.total_max_supply, ado.descriptor.decimal_point)
<< ENDL << "Current Supply: " << print_asset_money(ado.descriptor.current_supply, ado.descriptor.decimal_point)
<< ENDL << "Decimal Point: " << ado.descriptor.decimal_point;
add_rollback_event(ptc.height, asset_register_event{ asset_id });
WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0);
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
}
else
{
// update event of the asset that we not control, skip
break;
}
}
else
{
//asset had been updated
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
//update event for asset that we control, check if ownership is still ours
if (ado.descriptor.owner != m_account.get_public_address().spend_public_key && !it->second.thirdparty_custody)
{
//ownership of the asset had been transfered
add_rollback_event(ptc.height, asset_unown_event{ it->first, it->second });
m_own_asset_descriptors.erase(it);
std::stringstream ss;
ss << "Asset ownership lost:"
<< ENDL << "asset id: " << asset_id
<< ENDL << "New owner: " << ado.descriptor.owner
<< ENDL << "Name: " << ado.descriptor.full_name
<< ENDL << "Ticker: " << ado.descriptor.ticker
<< ENDL << "Total Max Supply: " << print_asset_money(ado.descriptor.total_max_supply, ado.descriptor.decimal_point)
<< ENDL << "Current Supply: " << print_asset_money(ado.descriptor.current_supply, ado.descriptor.decimal_point)
<< ENDL << "Decimal Point: " << ado.descriptor.decimal_point;
add_rollback_event(ptc.height, asset_register_event{ asset_id });
WLT_LOG_MAGENTA(ss.str(), LOG_LEVEL_0);
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
}
else
{
//just an update of the asset
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
}
}
}
} while (false);
@ -544,7 +588,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
all values m_payments entry, use this strict policy is required to protect exchanges from being feeded with
useless outputs
*/
uint64_t max_out_unlock_time = 0;
ptc.max_out_unlock_time = 0;
std::vector<wallet_out_info> outs;
//uint64_t sum_of_native_outs = 0; // TODO: @#@# correctly calculate tx_money_got_in_outs for post-HF4
@ -640,21 +684,29 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
auto it = m_key_images.find(ki);
if (it != m_key_images.end())
{
// Issue that has been discovered by Luke Parker (twitter: @kayabaNerve)
// An attacker can quickly issue transaction that use same outputs ephemeral keys + same tx key, as a result both
// transaction's outputs would have same key image, so the wallet should have smart approach to this situation, ie
// use output that offer biggest output value.(tokens?)
// We encountered an output with a key image already seen. This implies only one can be spent in the future (assuming the first isn't spent yet).
// To address this, we disregard such outputs and log a warning.
//
// It was later revealed that auditable wallets could still be vulnerable: an attacker might quickly broadcast a transaction
// using the same output's ephemeral keys + the same tx pub key. If the malicious transaction (potentially for a lesser amount)
// arrives first, the recipient would be unable to spend the funds from the second, real transaction.
// This attack vector was highlighted by Luke Parker (twitter: @kayabaNerve), who suggested selecting the output with the largest amount.
// Sadly, this fix only applies to classic RingCT transactions and is incompatible with our use of Confidential Assets.
// Consequently, we adopted a solution suggested by @crypto_zoidberg: verifying in zero knowledge that the sender possesses the transaction's
// secret key. This verification is integrated with the balance proof (double Schnorr proof).
//
// However, we continue to omit outputs with duplicate key images since they could originate from the same source (albeit impractically).
// -- sowle
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "m_key_images entry has wrong m_transfers index, it->second: " << it->second << ", m_transfers.size(): " << m_transfers.size());
const transfer_details& local_td = m_transfers[it->second];
std::stringstream ss;
ss << "tx " << ptc.tx_hash() << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" <<
local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height <<
". This output can't ever be spent and will be skipped.";
ss << "tx " << ptc.tx_hash() << " @ block " << height << " has output #" << o << " with amount " << out.amount;
if (!out.is_native_coin())
ss << "(asset_id: " << out.asset_id << ") ";
ss << "and key image " << ki << " that has already been seen in output #" << local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx)
<< " @ block " << local_td.m_spent_height << ". This output can't ever be spent and will be skipped.";
WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0);
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_yellow, ss.str());
@ -671,9 +723,12 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
out_get_mixin_attr(out_v) != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
{
std::stringstream ss;
ss << "output #" << o << " from tx " << ptc.tx_hash() << " with amount " << print_money_brief(outs[i_in_outs].amount)
ss << "output #" << o << " from tx " << ptc.tx_hash();
if (!out.is_native_coin())
ss << " asset_id: " << out.asset_id;
ss << " with amount " << print_money_brief(out.amount)
<< " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)out_get_mixin_attr(out_v) << ". Output is IGNORED.";
WLT_LOG_RED(ss.str(), LOG_LEVEL_0);
WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0);
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str());
//if (out.is_native_coin())
@ -777,8 +832,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
m_amount_gindex_to_transfer_id[amount_gindex_pair] = transfer_index;
}
if (max_out_unlock_time < get_tx_unlock_time(tx, o))
max_out_unlock_time = get_tx_unlock_time(tx, o);
if (ptc.max_out_unlock_time < get_tx_unlock_time(tx, o))
ptc.max_out_unlock_time = get_tx_unlock_time(tx, o);
if (out_type_to_key || out_type_zc)
{
@ -832,40 +887,12 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
}
}
std::string payment_id;
if (has_in_transfers && get_payment_id_from_tx(tx.attachment, payment_id) && payment_id.size())
{
payment_details payment;
payment.m_tx_hash = ptc.tx_hash();
payment.m_amount = 0;
payment.m_block_height = height;
payment.m_unlock_time = max_out_unlock_time;
for (const auto& bce : ptc.total_balance_change)
{
if (bce.second > 0)
{
if (bce.first == currency::native_coin_asset_id)
{
payment.m_amount = static_cast<uint64_t>(bce.second);
}else
{
payment.subtransfers.push_back(payment_details_subtransfer{ bce.first, static_cast<uint64_t>(bce.second)});
}
}
}
m_payments.emplace(payment_id, payment);
WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount) << "subtransfers = " << payment.subtransfers.size());
}
if (ptc.spent_own_native_inputs)
//check if there are asset_registration that belong to this wallet
const asset_descriptor_operation* pado = get_type_in_variant_container<const asset_descriptor_operation>(tx.extra);
if (pado && (ptc.employed_entries.receive.size() || ptc.employed_entries.spent.size() || pado->descriptor.owner == m_account.get_public_address().spend_public_key))
{
//check if there are asset_registration that belong to this wallet
asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
if (get_type_in_variant_container(tx.extra, ado))
{
process_ado_in_new_transaction(ado, ptc);
}
process_ado_in_new_transaction(*pado, ptc);
}
if (has_in_transfers || has_out_transfers || is_derivation_used_to_encrypt(tx, derivation) || ptc.employed_entries.spent.size())
@ -917,7 +944,7 @@ void wallet2::prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_i
{
LOG_ERROR("wti.payment_id is expected to be empty. Go ahead.");
}
get_payment_id_from_tx(decrypted_att, wti.payment_id);
get_payment_id_from_decrypted_container(decrypted_att, wti.payment_id);
for (const auto& item : decrypted_att)
{
@ -1261,7 +1288,7 @@ bool wallet2::handle_proposal(wallet_public::wallet_transfer_info& wti, const bc
ed.is_a = cpd.a_addr.spend_public_key == m_account.get_keys().account_address.spend_public_key;
change_contract_state(ed, wallet_public::escrow_contract_details_basic::proposal_sent, ms_id, wti);
ed.private_detailes = cpd;
currency::get_payment_id_from_tx(decrypted_items, ed.payment_id);
currency::get_payment_id_from_decrypted_container(decrypted_items, ed.payment_id);
ed.proposal = prop;
ed.height = wti.height;
wti.contract.resize(1);
@ -1530,8 +1557,42 @@ void wallet2::prepare_wti(wallet_public::wallet_transfer_info& wti, const proces
}
prepare_wti_decrypted_attachments(wti, decrypted_att);
process_contract_info(wti, decrypted_att);
process_payment_id_for_wti(wti, tx_process_context);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::process_payment_id_for_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& ptc)
{
//if(this->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))
{
if (wti.get_native_is_income() && wti.payment_id.size())
{
payment_details payment;
payment.m_tx_hash = wti.tx_hash;
payment.m_amount = 0;
payment.m_block_height = wti.height;
payment.m_unlock_time = ptc.max_out_unlock_time;
for (const auto& bce : ptc.total_balance_change)
{
if (bce.second > 0)
{
if (bce.first == currency::native_coin_asset_id)
{
payment.m_amount = static_cast<uint64_t>(bce.second);
}
else
{
payment.subtransfers.push_back(payment_details_subtransfer{ bce.first, static_cast<uint64_t>(bce.second) });
}
}
}
m_payments.emplace(wti.payment_id, payment);
WLT_LOG_L2("Payment found, id (hex): " << epee::string_tools::buff_to_hex_nodelimer(wti.payment_id) << ", tx: " << payment.m_tx_hash << ", amount: " << print_money_brief(payment.m_amount) << "subtransfers = " << payment.subtransfers.size());
}
}
return true;
}
void wallet2::rise_on_transfer2(const wallet_public::wallet_transfer_info& wti)
{
PROFILE_FUNC("wallet2::rise_on_transfer2");
@ -1582,7 +1643,7 @@ void wallet2::load_wti_from_process_transaction_context(wallet_public::wallet_tr
{
wti.remote_addresses = tx_process_context.recipients;
wti.remote_aliases = tx_process_context.remote_aliases;
for (const auto bce : tx_process_context.total_balance_change)
for (const auto& bce : tx_process_context.total_balance_change)
{
wallet_public::wallet_sub_transfer_info wsti = AUTO_VAL_INIT(wsti);
wsti.asset_id = bce.first;
@ -3322,7 +3383,7 @@ uint64_t wallet2::balance(uint64_t& unlocked, uint64_t& awaiting_in, uint64_t& a
return total;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance(crypto::public_key asset_id, uint64_t& unlocked) const
uint64_t wallet2::balance(const crypto::public_key& asset_id, uint64_t& unlocked) const
{
std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances;
uint64_t dummy;
@ -3336,6 +3397,12 @@ uint64_t wallet2::balance(crypto::public_key asset_id, uint64_t& unlocked) const
return it->second.total;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::balance(const crypto::public_key& asset_id) const
{
uint64_t dummy = 0;
return balance(asset_id, dummy);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const
{
mined = 0;
@ -3804,7 +3871,7 @@ void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::trans
throw;
}
add_sent_tx_detailed_info(tx, ft.ftp.prepared_destinations, ft.ftp.selected_transfers);
add_sent_tx_detailed_info(tx, ft.ftp.attachments, ft.ftp.prepared_destinations, ft.ftp.selected_transfers);
m_tx_keys.insert(std::make_pair(tx_hash, ft.one_time_key));
if (m_watch_only)
@ -4847,7 +4914,7 @@ void wallet2::deploy_new_asset(const currency::asset_descriptor_base& asset_info
currency::asset_descriptor_operation ado = AUTO_VAL_INIT(ado);
bool r = get_type_in_variant_container(result_tx.extra, ado);
CHECK_AND_ASSERT_THROW_MES(r, "Failed find asset info in tx");
calculate_asset_id(ado.descriptor.owner, nullptr, &new_asset_id);
CHECK_AND_ASSERT_THROW_MES(get_or_calculate_asset_id(ado, nullptr, &new_asset_id), "get_or_calculate_asset_id failed");
m_custom_assets[new_asset_id] = ado.descriptor;
}
@ -4871,7 +4938,8 @@ void wallet2::emmit_asset(const crypto::public_key asset_id, std::vector<currenc
ctp.dsts = destinations;
ctp.extra.push_back(asset_emmit_info);
ctp.need_at_least_1_zc = true;
ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
ctp.ado_current_asset_owner = rsp.asset_descriptor.owner;
//ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr);
@ -4890,7 +4958,33 @@ void wallet2::update_asset(const crypto::public_key asset_id, const currency::as
construct_tx_param ctp = get_default_construct_tx_param();
ctp.extra.push_back(asset_update_info);
ctp.need_at_least_1_zc = true;
ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
bool r = this->daemon_get_asset_info(asset_id, adb);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
ctp.ado_current_asset_owner = adb.owner;
finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr);
result_tx = ft.tx;
}
//----------------------------------------------------------------------------------------------------
void wallet2::transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx)
{
auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
currency::asset_descriptor_base adb = AUTO_VAL_INIT(adb);
bool r = this->daemon_get_asset_info(asset_id, adb);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to get asset info from daemon");
asset_descriptor_operation asset_update_info = AUTO_VAL_INIT(asset_update_info);
asset_update_info.descriptor = adb;
asset_update_info.operation_type = ASSET_DESCRIPTOR_OPERATION_UPDATE;
asset_update_info.opt_asset_id = asset_id;
asset_update_info.descriptor.owner = new_owner;
construct_tx_param ctp = get_default_construct_tx_param();
ctp.ado_current_asset_owner = adb.owner;
ctp.extra.push_back(asset_update_info);
finalized_tx ft = AUTO_VAL_INIT(ft);
this->transfer(ctp, ft, true, nullptr);
@ -4899,8 +4993,8 @@ void wallet2::update_asset(const crypto::public_key asset_id, const currency::as
//----------------------------------------------------------------------------------------------------
void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx)
{
auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
//auto own_asset_entry_it = m_own_asset_descriptors.find(asset_id);
//CHECK_AND_ASSERT_THROW_MES(own_asset_entry_it != m_own_asset_descriptors.end(), "Failed find asset_id " << asset_id << " in own assets list");
COMMAND_RPC_GET_ASSET_INFO::request req;
req.asset_id = asset_id;
COMMAND_RPC_GET_ASSET_INFO::response rsp;
@ -4923,7 +5017,7 @@ void wallet2::burn_asset(const crypto::public_key asset_id, uint64_t amount_to_b
construct_tx_param ctp = get_default_construct_tx_param();
ctp.extra.push_back(asset_burn_info);
ctp.need_at_least_1_zc = true;
ctp.asset_deploy_control_key = own_asset_entry_it->second.control_key;
ctp.ado_current_asset_owner = rsp.asset_descriptor.owner;
ctp.dsts.push_back(dst_to_burn);
finalized_tx ft = AUTO_VAL_INIT(ft);
@ -5380,7 +5474,7 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details&
send_transaction_to_network(tx);
mark_transfers_as_spent(ftp.selected_transfers, std::string("escrow proposal sent, tx <") + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">, contract: " + epee::string_tools::pod_to_hex(ms_id));
add_sent_tx_detailed_info(tx, ftp.prepared_destinations, ftp.selected_transfers);
add_sent_tx_detailed_info(tx, ftp.attachments, ftp.prepared_destinations, ftp.selected_transfers);
print_tx_sent_message(tx, "(from multisig)", fee);
}
@ -5548,7 +5642,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal
proposal.tx_template = finalize_result.tx;
wallet_public::ionic_swap_proposal_context ispc = AUTO_VAL_INIT(ispc);
ispc.gen_context = finalize_result.ftp.gen_context;
ispc.one_time_skey = finalize_result.one_time_key;
//ispc.one_time_skey = finalize_result.one_time_key;
std::string proposal_context_blob = t_serializable_object_to_blob(ispc);
proposal.encrypted_context = crypto::chacha_crypt(static_cast<const std::string&>(proposal_context_blob), finalize_result.derivation);
return true;
@ -5586,7 +5680,7 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
r = t_unserializable_object_from_blob(ionic_context, decrypted_raw_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to unserialize decrypted ionic_context");
r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context, ionic_context.one_time_skey);
r = validate_tx_output_details_againt_tx_generation_context(tx, ionic_context.gen_context);
THROW_IF_FALSE_WALLET_INT_ERR_EX(r, "Failed to validate decrypted ionic_context");
std::unordered_map<crypto::public_key, uint64_t> amounts_provided_by_a;
@ -5754,7 +5848,7 @@ bool wallet2::accept_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
construct_tx_param construct_param = get_default_construct_tx_param();
construct_param.fee = additional_fee;
crypto::secret_key one_time_key = ionic_context.one_time_skey;
crypto::secret_key one_time_key = ionic_context.gen_context.tx_key.sec; // TODO: figure out this mess with tx sec key -- sowle
construct_param.crypt_address = m_account.get_public_address();
construct_param.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE;
construct_param.mark_tx_as_complete = true;
@ -6250,12 +6344,12 @@ void wallet2::send_transaction_to_network(const transaction& tx)
}
//----------------------------------------------------------------------------------------------------------------
void wallet2::add_sent_tx_detailed_info(const transaction& tx,
void wallet2::add_sent_tx_detailed_info(const transaction& tx, const std::vector<currency::attachment_v>& decrypted_att,
const std::vector<currency::tx_destination_entry>& destinations,
const std::vector<uint64_t>& selected_transfers)
{
payment_id_t payment_id;
get_payment_id_from_tx(tx.attachment, payment_id);
get_payment_id_from_decrypted_container(decrypted_att, payment_id);
std::vector<std::string> recipients;
std::unordered_set<account_public_address> used_addresses;
@ -6916,7 +7010,8 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
const currency::transaction& tx_for_mode_separate = msc.tx_for_mode_separate;
assets_selection_context needed_money_map = get_needed_money(ctp.fee, ctp.dsts);
ftp.asset_control_key = ctp.asset_deploy_control_key;
ftp.ado_current_asset_owner = ctp.ado_current_asset_owner;
ftp.pthirdparty_sign_handler = ctp.pthirdparty_sign_handler;
//
// TODO @#@# need to do refactoring over this part to support hidden amounts and asset_id
//
@ -7057,7 +7152,7 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
//TIME_MEASURE_START(add_sent_tx_detailed_info_time);
if (broadcast_tx)
add_sent_tx_detailed_info(result.tx, ftp.prepared_destinations, ftp.selected_transfers);
add_sent_tx_detailed_info(result.tx, ftp.attachments, ftp.prepared_destinations, ftp.selected_transfers);
//TIME_MEASURE_FINISH(add_sent_tx_detailed_info_time);
/* TODO
@ -7181,7 +7276,7 @@ void wallet2::check_and_throw_if_self_directed_tx_with_payment_id_requested(cons
// it's self-directed tx
payment_id_t pid;
bool has_payment_id = get_payment_id_from_tx(ctp.attachments, pid) && !pid.empty();
bool has_payment_id = get_payment_id_from_decrypted_container(ctp.attachments, pid) && !pid.empty();
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!has_payment_id, "sending funds to yourself with payment id is not allowed");
}
//----------------------------------------------------------------------------------------------------
@ -7331,8 +7426,9 @@ void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public
currency::finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
ftp.tx_version = this->get_current_tx_version();
bool is_hf4 = this->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM);
if (!payment_id.empty())
set_payment_id_to_tx(ftp.attachments, payment_id);
set_payment_id_to_tx(ftp.attachments, payment_id, is_hf4);
// put encrypted payer info into the extra
ftp.crypt_address = destination_addr;

View file

@ -323,6 +323,7 @@ namespace tools
multisig_entries_map* pmultisig_entries = nullptr;
crypto::public_key tx_pub_key = currency::null_pkey;
uint64_t tx_expiration_ts_median = 0;
uint64_t max_out_unlock_time = 0;
const crypto::hash& tx_hash() const
{
@ -391,9 +392,10 @@ namespace tools
void emmit_asset(const crypto::public_key asset_id, std::vector<currency::tx_destination_entry>& destinations, currency::transaction& result_tx);
void update_asset(const crypto::public_key asset_id, const currency::asset_descriptor_base new_descriptor, currency::transaction& result_tx);
void burn_asset(const crypto::public_key asset_id, uint64_t amount_to_burn, currency::transaction& result_tx);
void transfer_asset_ownership(const crypto::public_key asset_id, const crypto::public_key& new_owner, currency::transaction& result_tx);
bool daemon_get_asset_info(const crypto::public_key& asset_id, currency::asset_descriptor_base& adb);
const std::unordered_map<crypto::public_key, wallet_own_asset_context>& get_own_assets() const { return m_own_asset_descriptors; }
bool set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy);
void set_pos_utxo_count_limits_for_defragmentation_tx(uint64_t min_outs, uint64_t max_outs); // don't create UTXO defrag. tx if there are less than 'min_outs' outs; don't put more than 'max_outs' outs
void set_pos_decoys_count_for_defragmentation_tx(size_t decoys_count);
@ -404,7 +406,8 @@ namespace tools
uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined, const crypto::public_key& asset_id = currency::native_coin_asset_id) const;
bool balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const;
bool balance(std::list<wallet_public::asset_balance_entry>& balances, uint64_t& mined) const;
uint64_t balance(crypto::public_key asset_id, uint64_t& unloked) const;
uint64_t balance(const crypto::public_key& asset_id, uint64_t& unlocked) const;
uint64_t balance(const crypto::public_key& asset_id) const;
uint64_t balance(uint64_t& unloked) const;
@ -688,6 +691,7 @@ namespace tools
bool validate_sign(const std::string& buff, const crypto::signature& sig, const crypto::public_key& pkey);
bool encrypt_buffer(const std::string& buff, std::string& res_buff);
bool decrypt_buffer(const std::string& buff, std::string& res_buff);
bool is_in_hardfork_zone(uint64_t hardfork_index) const;
construct_tx_param get_default_construct_tx_param();
@ -739,6 +743,7 @@ private:
void prepare_wti_decrypted_attachments(wallet_public::wallet_transfer_info& wti, const std::vector<currency::payload_items_v>& decrypted_att);
void handle_money(const currency::block& b, const process_transaction_context& tx_process_context);
void load_wti_from_process_transaction_context(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context);
bool process_payment_id_for_wti(wallet_public::wallet_transfer_info& wti, const process_transaction_context& tx_process_context);
void handle_pulled_blocks(size_t& blocks_added, std::atomic<bool>& stop,
currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks);
@ -815,7 +820,8 @@ private:
void load_keys2ki(bool create_if_not_exist, bool& need_to_resync);
void send_transaction_to_network(const currency::transaction& tx);
void add_sent_tx_detailed_info(const currency::transaction& tx,
void add_sent_tx_detailed_info(const currency::transaction& tx,
const std::vector<currency::attachment_v>& decrypted_att,
const std::vector<currency::tx_destination_entry>& destinations,
const std::vector<uint64_t>& selected_indicies);
void mark_transfers_as_spent(const std::vector<uint64_t>& selected_transfers, const std::string& reason = std::string());
@ -836,7 +842,6 @@ private:
uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(uint64_t amount, const std::vector<currency::txout_ref_v> & key_offsets);
uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_to_key& intk);
uint64_t get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_zc_input& inzc);
bool is_in_hardfork_zone(uint64_t hardfork_index) const;
uint8_t out_get_mixin_attr(const currency::tx_out_v& out_t);
const crypto::public_key& out_get_pub_key(const currency::tx_out_v& out_t, std::list<currency::htlc_info>& htlc_info_list);
bool expand_selection_with_zc_input(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes);

View file

@ -199,6 +199,7 @@ namespace tools
END_SERIALIZE()
};
struct construct_tx_param
{
// preparing data for tx
@ -223,7 +224,9 @@ namespace tools
bool shuffle = false;
bool create_utxo_defragmentation_tx = false;
bool need_at_least_1_zc = false;
crypto::secret_key asset_deploy_control_key = currency::null_skey;
//crypto::secret_key asset_deploy_control_key = currency::null_skey;
currency::thirdparty_sign_handler* pthirdparty_sign_handler = nullptr;
crypto::public_key ado_current_asset_owner = currency::null_pkey;
};
struct mode_separate_context
@ -255,13 +258,11 @@ namespace tools
struct wallet_own_asset_context
{
currency::asset_descriptor_base asset_descriptor;
crypto::secret_key control_key;
//uint64_t height = 0;
bool thirdparty_custody = false;
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(asset_descriptor)
BOOST_SERIALIZE(control_key)
//BOOST_SERIALIZE(height)
BOOST_SERIALIZE(thirdparty_custody)
END_BOOST_SERIALIZATION()
};

View file

@ -13,9 +13,20 @@ struct wde_construct_tx_handle_asset_descriptor_operation
};
//Wallet Debug Events
struct wde_construct_tx_handle_asset_descriptor_operation_before_seal
{
currency::asset_descriptor_operation* pado;
};
struct wde_construct_tx_handle_asset_descriptor_operation_before_burn
{
currency::asset_descriptor_operation* pado;
};
struct wde_construct_tx_after_asset_ownership_proof_generated
{
currency::asset_operation_ownership_proof* pownership_proof;
};

View file

@ -273,18 +273,28 @@ namespace wallet_public
}
};
struct wallet_transfer_info_old : public wallet_transfer_info
{
uint64_t amount = 0;
bool is_income = false;
//uint64_t amount = 0;
//bool is_income = false;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(is_income)
KV_SERIALIZE(amount)
KV_SERIALIZE_EPHEMERAL_N(uint64_t, wallet_transfer_info_to_amount, "amount")
KV_SERIALIZE_EPHEMERAL_N(bool, wallet_transfer_info_to_is_income, "is_income")
//KV_SERIALIZE(amount)
KV_CHAIN_BASE(wallet_transfer_info)
END_KV_SERIALIZE_MAP()
static uint64_t wallet_transfer_info_to_amount(const wallet_transfer_info_old& wtio)
{
return wtio.get_native_amount();
}
static bool wallet_transfer_info_to_is_income(const wallet_transfer_info_old& wtio)
{
return wtio.get_native_is_income();
}
};
@ -1226,6 +1236,29 @@ namespace wallet_public
};
};
struct COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY
{
typedef COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request request;
struct response
{
std::list<wallet_transfer_info_old> in;
std::list<wallet_transfer_info_old> out;
//std::list<wallet_transfer_info> pending;
//std::list<wallet_transfer_info> failed;
std::list<wallet_transfer_info_old> pool;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(in)
KV_SERIALIZE(out)
//KV_SERIALIZE(pending)
//KV_SERIALIZE(failed)
KV_SERIALIZE(pool)
END_KV_SERIALIZE_MAP()
};
};
struct htlc_entry_info
{
currency::account_public_address counterparty_address;
@ -1407,12 +1440,10 @@ namespace wallet_public
struct ionic_swap_proposal_context
{
currency::tx_generation_context gen_context;
crypto::secret_key one_time_skey;
BEGIN_SERIALIZE_OBJECT()
VERSION(0) //use VERSION_TO_MEMBER if it's more then 0
FIELD(gen_context)
FIELD(one_time_skey)
END_SERIALIZE()
};

View file

@ -276,6 +276,16 @@ namespace tools
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
template<typename t_from, typename t_to>
void copy_wallet_transfer_info_old_container(const t_from& from_c, t_to& to_c)
{
for (const auto& item : from_c)
{
to_c.push_back(wallet_public::wallet_transfer_info_old());
*static_cast<wallet_public::wallet_transfer_info*>(&to_c.back()) = item;
}
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
//this is legacy api, should be removed after successful transition to HF4
@ -286,20 +296,7 @@ namespace tools
res.pi = rsp2.pi;
res.total_transfers = rsp2.total_transfers;
res.last_item_index = rsp2.last_item_index;
for (const auto& item : rsp2.transfers)
{
res.transfers.push_back(wallet_public::wallet_transfer_info_old());
*static_cast<wallet_public::wallet_transfer_info*>(&res.transfers.back()) = item;
for (const auto& subitem : item.subtransfers)
{
if (subitem.asset_id == currency::native_coin_asset_id)
{
res.transfers.back().amount = subitem.amount;
res.transfers.back().is_income = subitem.is_income;
}
}
}
copy_wallet_transfer_info_old_container(rsp2.transfers, res.transfers);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
@ -413,7 +410,7 @@ namespace tools
std::vector<currency::attachment_v>& attachments = ctp.attachments;
std::vector<currency::extra_v>& extra = ctp.extra;
if (!payment_id.empty() && !currency::set_payment_id_to_tx(attachments, payment_id))
if (!payment_id.empty() && !currency::set_payment_id_to_tx(attachments, payment_id, w.get_wallet()->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
er.message = std::string("payment id ") + payment_id + " is invalid and can't be set";
@ -699,8 +696,19 @@ namespace tools
return true;
}
bool wallet_rpc_server::on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response res_origin;
bool r = this->on_search_for_transactions2(req, res_origin, er, cntx);
copy_wallet_transfer_info_old_container(res_origin.in, res.in);
copy_wallet_transfer_info_old_container(res_origin.out, res.out);
copy_wallet_transfer_info_old_container(res_origin.pool, res.pool);
return r;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx)
bool wallet_rpc_server::on_search_for_transactions2(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
bool tx_id_specified = req.tx_id != currency::null_hash;
@ -753,6 +761,7 @@ namespace tools
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_mining_history(const wallet_public::COMMAND_RPC_GET_MINING_HISTORY::request& req, wallet_public::COMMAND_RPC_GET_MINING_HISTORY::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();

View file

@ -105,7 +105,8 @@ namespace tools
MAP_JON_RPC_WE("sweep_below", on_sweep_below, wallet_public::COMMAND_SWEEP_BELOW)
MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_public::COMMAND_SIGN_TRANSFER)
MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_public::COMMAND_SUBMIT_TRANSFER)
MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS)
MAP_JON_RPC_WE("search_for_transactions", on_search_for_transactions, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY)
MAP_JON_RPC_WE("search_for_transactions2", on_search_for_transactions2, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS)
MAP_JON_RPC_WE("get_restore_info", on_getwallet_restore_info, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO)
MAP_JON_RPC_WE("get_seed_phrase_info", on_get_seed_phrase_info, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO)
MAP_JON_RPC_WE("get_mining_history", on_get_mining_history, wallet_public::COMMAND_RPC_GET_MINING_HISTORY)
@ -161,7 +162,8 @@ namespace tools
bool on_sweep_below(const wallet_public::COMMAND_SWEEP_BELOW::request& req, wallet_public::COMMAND_SWEEP_BELOW::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_sign_transfer(const wallet_public::COMMAND_SIGN_TRANSFER::request& req, wallet_public::COMMAND_SIGN_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_submit_transfer(const wallet_public::COMMAND_SUBMIT_TRANSFER::request& req, wallet_public::COMMAND_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_search_for_transactions(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_search_for_transactions2(const wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_mining_history(const wallet_public::COMMAND_RPC_GET_MINING_HISTORY::request& req, wallet_public::COMMAND_RPC_GET_MINING_HISTORY::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_register_alias(const wallet_public::COMMAND_RPC_REGISTER_ALIAS::request& req, wallet_public::COMMAND_RPC_REGISTER_ALIAS::response& res, epee::json_rpc::error& er, connection_context& cntx);

View file

@ -188,6 +188,7 @@ bool wallets_manager::init_command_line(int argc, char* argv[], std::string& fai
command_line::add_arg(desc_cmd_sett, arg_qt_dev_tools);
command_line::add_arg(desc_cmd_sett, command_line::arg_no_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_force_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_process_predownload_from_path);
command_line::add_arg(desc_cmd_sett, command_line::arg_validate_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_predownload_link);
command_line::add_arg(desc_cmd_only, command_line::arg_deeplink);
@ -1533,18 +1534,17 @@ std::string wallets_manager::transfer(uint64_t wallet_id, const view::transfer_p
dsts.back().asset_id = d.asset_id;
}
GET_WALLET_BY_ID(wallet_id, w);
if (payment_id.size())
{
if (!currency::is_payment_id_size_ok(payment_id))
return API_RETURN_CODE_BAD_ARG_WRONG_PAYMENT_ID; // payment id is too big
if (!currency::set_payment_id_to_tx(attachments, payment_id))
if (!currency::set_payment_id_to_tx(attachments, payment_id, w->get()->is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM)))
return API_RETURN_CODE_INTERNAL_ERROR;
}
GET_WALLET_BY_ID(wallet_id, w);
//set transaction unlock time if it was specified by user
uint64_t unlock_time = 0;

View file

@ -28,7 +28,7 @@ add_executable(net_load_tests_srv net_load_tests/srv.cpp)
add_dependencies(coretests version)
target_link_libraries(coretests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
target_link_libraries(coretests rpc wallet currency_core common crypto zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
target_link_libraries(functional_tests rpc wallet currency_core crypto common zlibstatic ethash libminiupnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
target_link_libraries(hash-tests crypto ethash)
target_link_libraries(hash-target-tests crypto currency_core ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})

View file

@ -1055,6 +1055,7 @@ bool test_generator::construct_pow_block_with_alias_info_in_coinbase(const accou
miner_tx.vout.clear();
tx_generation_context tx_gen_context{};
tx_gen_context.set_tx_key(tx_key);
tx_gen_context.resize(/* ZC ins: */ 0, /* OUTS: */ alias_cost != 0 ? 3 : 2);
std::set<unsigned short> deriv_cache;
finalized_tx fin_tx_stub{};

View file

@ -1085,6 +1085,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(wallet_rpc_integrated_address);
GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer);
GENERATE_AND_PLAY(wallet_rpc_transfer);
GENERATE_AND_PLAY_HF(wallet_rpc_exchange_suite, "3,4");
GENERATE_AND_PLAY(wallet_chain_switch_with_spending_the_same_ki);
GENERATE_AND_PLAY(wallet_sending_to_integrated_address);

View file

@ -11,65 +11,6 @@
#include "wallet/wallet_debug_events_definitions.h"
using namespace currency;
/*
struct debug_context_event_1
{
int& i;
std::string& s;
};
//#define RAISE_DEBUG_EVENT dw.handle_type
void test_test()
{
epee::misc_utils::events_dispatcher ed;
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//thus code will be called in the tests
ed.SUBSCIRBE_DEBUG_EVENT<debug_context_event_1>([&](debug_context_event_1& d)
{
//here some operations
LOG_PRINT_L0("lala: " << d.i << d.s);
//
d.i = 10;
d.s = "33333";
});
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
//this code will be in the wallet and helper functions
int i = 22;
std::string sss = "11111";
ed.RAISE_DEBUG_EVENT(debug_context_event_1{i, sss });
LOG_PRINT_L0("lala: " << i << sss);
}
*/
//------------------------------------------------------------------------------
#define AMOUNT_TO_TRANSFER_MULTIASSETS_BASIC (TESTS_DEFAULT_FEE)
@ -97,6 +38,7 @@ bool multiassets_basic_test::generate(std::vector<test_event_entry>& events) con
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
//TODO: Need to make sure REWIND_BLOCKS_N and other coretests codebase are capable of following hardfork4 rules
//in this test hardfork4 moment moved to runtime section
//REWIND_BLOCKS_N_WITH_TIME(events, blk_2_inital, blk_0, alice_acc, 2);
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3);
DO_CALLBACK(events, "c1");
@ -115,7 +57,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
alice_wlt->get_account().set_createtime(0);
asset_descriptor_base adb = AUTO_VAL_INIT(adb);
adb.total_max_supply = 1000000000000000000; //1M coins
adb.total_max_supply = 10000000000000000000ULL; //1M coins
adb.full_name = "Test coins";
adb.ticker = "TCT";
adb.decimal_point = 12;
@ -141,31 +83,13 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
miner_wlt->refresh();
alice_wlt->refresh();
uint64_t mined = 0;
std::unordered_map<crypto::public_key, tools::wallet_public::asset_balance_entry_base> balances;
miner_wlt->balance(balances, mined);
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(miner_wlt->balance() == uint64_t(17517225990000000000ULL), false, "Failed to find needed asset in result balances");
auto it_asset = balances.find(asset_id);
auto it_native = balances.find(currency::native_coin_asset_id);
CHECK_AND_ASSERT_MES(it_asset != balances.end() && it_native != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == uint64_t(17517225990000000000), false, "Failed to find needed asset in result balances");
balances.clear();
alice_wlt->balance(balances, mined);
it_asset = balances.find(asset_id);
it_native = balances.find(currency::native_coin_asset_id);
CHECK_AND_ASSERT_MES(it_asset != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native == balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(alice_wlt->balance() == 0, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
miner_wlt->transfer(AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, alice_wlt->get_account().get_public_address(), asset_id);
//pass over hardfork
@ -173,11 +97,9 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
alice_wlt->refresh();
uint64_t last_alice_balances = alice_wlt->balance(asset_id, mined);
uint64_t last_alice_balances = alice_wlt->balance(asset_id);
CHECK_AND_ASSERT_MES(last_alice_balances == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC + AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC/2, false, "Failed to find needed asset in result balances");
{
try {
@ -193,7 +115,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
}
miner_wlt->refresh();
uint64_t last_miner_balance = miner_wlt->balance(asset_id, mined);
uint64_t last_miner_balance = miner_wlt->balance(asset_id);
asset_descriptor_base asset_info = AUTO_VAL_INIT(asset_info);
@ -211,7 +133,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
//test update function
asset_info.meta_info = "{\"some\": \"info\"}";
miner_wlt->update_asset(asset_id, asset_info, tx);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 2);
r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, 2);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
asset_descriptor_base asset_info2 = AUTO_VAL_INIT(asset_info2);
@ -228,8 +150,8 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
miner_wlt->refresh();
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id, mined) == last_miner_balance + destinations[0].amount, false, "Miner balance wrong");
CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id, mined) == last_alice_balances + destinations[1].amount, false, "Alice balance wrong");
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == last_miner_balance + destinations[0].amount, false, "Miner balance wrong");
CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == last_alice_balances + destinations[1].amount, false, "Alice balance wrong");
asset_descriptor_base asset_info3 = AUTO_VAL_INIT(asset_info3);
r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info3);
@ -242,7 +164,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
miner_wlt->refresh();
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id, mined) == destinations[0].amount, false, "Miner balance wrong");
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == destinations[0].amount, false, "Miner balance wrong");
asset_descriptor_base asset_info4 = AUTO_VAL_INIT(asset_info4);
r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info4);
@ -252,10 +174,10 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
//------------------- tests that trying to break stuff -------------------
//tests that trying to break stuff
miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation>([&](const wde_construct_tx_handle_asset_descriptor_operation& o)
miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_after_asset_ownership_proof_generated>([&](const wde_construct_tx_after_asset_ownership_proof_generated& o)
{
crypto::signature s = currency::null_sig;
o.pado->opt_proof = s;
//crypto::signature s = currency::null_sig;
o.pownership_proof->gss = crypto::generic_schnorr_sig_s{};
});
@ -270,7 +192,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
c.get_tx_pool().purge_transactions();
miner_wlt->refresh();
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation>();
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL();
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
@ -317,17 +239,17 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
// check update_asset() with modified 'owner'
r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info);
CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info");
//r = c.get_blockchain_storage().get_asset_info(asset_id, asset_info);
//CHECK_AND_ASSERT_MES(r, false, "Failed to get_asset_info");
asset_info.owner = currency::keypair::generate().pub;
miner_wlt->update_asset(asset_id, asset_info, tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c);
CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed
c.get_tx_pool().purge_transactions();
miner_wlt->refresh();
//asset_info.owner = currency::keypair::generate().pub;
//miner_wlt->update_asset(asset_id, asset_info, tx);
//CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
//r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c);
//CHECK_AND_ASSERT_MES(!r, false, "block with a bad tx was unexpectedly mined");
//CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed
//c.get_tx_pool().purge_transactions();
//miner_wlt->refresh();
// check emmit_asset() with modified 'current_supply'
@ -346,13 +268,14 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
//------------------- tests that trying to break stuff -------------------
//test burn that burns more than tx has
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation_before_seal>();
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL();
miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation_before_seal>([&](const wde_construct_tx_handle_asset_descriptor_operation_before_seal& o)
miner_wlt->get_debug_events_dispatcher().SUBSCIRBE_DEBUG_EVENT<wde_construct_tx_handle_asset_descriptor_operation_before_burn>([&](const wde_construct_tx_handle_asset_descriptor_operation_before_burn& o)
{
o.pado->descriptor.current_supply -= 1000000;
});
miner_wlt->burn_asset(asset_id, 10000000000000, tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c);
@ -360,8 +283,39 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed
c.get_tx_pool().purge_transactions();
miner_wlt->refresh();
miner_wlt->get_debug_events_dispatcher().UNSUBSCRIBE_ALL();
//
miner_wlt->transfer_asset_ownership(asset_id, alice_wlt->get_account().get_public_address().spend_public_key, tx);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
r = mine_next_pow_block_in_playtime(miner_wlt->get_account().get_public_address(), c);
CHECK_AND_ASSERT_MES(r, false, "block with a bad tx was unexpectedly mined");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count()); // make sure tx was not confirmed
miner_wlt->refresh();
alice_wlt->refresh();
auto miner_own_assets = miner_wlt->get_own_assets();
auto alice_own_assets = alice_wlt->get_own_assets();
CHECK_AND_ASSERT_MES(miner_own_assets.size() == 0, false, "Miner wlt still think he own asset");
CHECK_AND_ASSERT_MES(alice_own_assets.size() == 1, false, "Alice still don't know she own asset");
//uint64_t balance_alice_native = alice_wlt->balance();
//uint64_t balance_miner_native = miner_wlt->balance();
uint64_t balance_alice_asset = alice_wlt->balance(asset_id);
uint64_t balance_miner_asset = miner_wlt->balance(asset_id);
alice_wlt->emmit_asset(asset_id, destinations, tx);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
miner_wlt->refresh();
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(miner_wlt->balance(asset_id) == balance_miner_asset + destinations[0].amount, false, "Miner balance wrong");
CHECK_AND_ASSERT_MES(alice_wlt->balance(asset_id) == balance_alice_asset + destinations[1].amount, false, "Alice balance wrong");
//TODO: attempt to emmmit from old key, attempt to emmit from more then max supply
return true;
}
@ -432,7 +386,7 @@ bool assets_and_explicit_native_coins_in_outs::generate(std::vector<test_event_e
MAKE_TX(events, tx_1, alice_acc, alice_acc, m_alice_initial_balance - TESTS_DEFAULT_FEE, blk_1r);
CHECK_AND_ASSERT_MES(tx_1.vout.size() == 2, false, "unexpected tx_1.vout.size : " << tx_1.vout.size());
// make sure that all tx_1 outputs have explicit hative coin asset id
// make sure that all tx_1 outputs have explicit native coin asset id
for(auto& out : tx_1.vout)
{
CHECK_AND_ASSERT_MES(out.type() == typeid(tx_out_zarcanum), false, "invalid out type");

View file

@ -298,5 +298,384 @@ bool wallet_rpc_transfer::c1(currency::core& c, size_t ev_index, const std::vect
CHECK_AND_ASSERT_MES(currency::count_type_in_variant_container<tx_payer>(pche->tx.extra) == 1, false, "tx_payer: incorrect count of items");
return true;
}
//------------------------------------------------------------------------------
wallet_rpc_exchange_suite::wallet_rpc_exchange_suite()
{
REGISTER_CALLBACK_METHOD(wallet_rpc_exchange_suite, c1);
}
bool wallet_rpc_exchange_suite::generate(std::vector<test_event_entry>& events) const
{
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // default callback will initialize core runtime config with m_hardforks
DO_CALLBACK(events, "c1");
return true;
}
struct transport
{
tools::wallet_rpc_server& m_rpc_srv;
transport(tools::wallet_rpc_server& rpc_srv):m_rpc_srv(rpc_srv)
{}
epee::net_utils::http::http_response_info m_response;
bool is_connected() { return true; }
template<typename t_a, typename t_b, typename t_c>
bool connect(t_a ta, t_b tb, t_c tc) { return true; }
template<typename dummy_t>
bool invoke(const std::string uri, const std::string method_, const std::string& body, const epee::net_utils::http::http_response_info** ppresponse_info, const dummy_t& d)
{
epee::net_utils::http::http_request_info query_info;
query_info.m_URI = uri;
query_info.m_body = body;
tools::wallet_rpc_server::connection_context ctx;
bool r = m_rpc_srv.handle_http_request(query_info, m_response, ctx);
if (ppresponse_info)
*ppresponse_info = &m_response;
return r;
}
};
template<typename request_t, typename response_t>
bool invoke_text_json_for_rpc(tools::wallet_rpc_server& srv, const std::string& method_name, const request_t& req, response_t& resp)
{
transport tr(srv);
bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", method_name, req, resp, tr);
return r;
}
#include "wallet_rpc_tests_legacy_defs.h"
std::string gen_payment_id(tools::wallet_rpc_server& custody_wlt_rpc)
{
pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request req = AUTO_VAL_INIT(req);
pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response resp = AUTO_VAL_INIT(resp);
bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp);
CHECK_AND_ASSERT_MES(r, "", "failed to call");
return resp.payment_id;
}
std::string get_integr_addr(tools::wallet_rpc_server& custody_wlt_rpc, const std::string payment_id)
{
pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request req = AUTO_VAL_INIT(req);
req.payment_id = payment_id;
pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response resp = AUTO_VAL_INIT(resp);
bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp);
CHECK_AND_ASSERT_MES(r, "", "failed to call");
return resp.integrated_address;
}
#define TRANSFER_COMMENT "SSDVSf"
std::string transfer_(std::shared_ptr<tools::wallet2> wlt, const std::string& address, uint64_t amount)
{
tools::wallet_rpc_server custody_wlt_rpc(wlt);
pre_hf4_api::COMMAND_RPC_TRANSFER::request tr_req = AUTO_VAL_INIT(tr_req);
tr_req.comment = TRANSFER_COMMENT;
tr_req.destinations.resize(1);
tr_req.destinations.back().address = address;
tr_req.destinations.back().amount = amount;
tr_req.fee = TX_DEFAULT_FEE;
pre_hf4_api::COMMAND_RPC_TRANSFER::response tr_resp = AUTO_VAL_INIT(tr_resp);
bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "transfer", tr_req, tr_resp);
CHECK_AND_ASSERT_MES(r, "", "failed to call");
return tr_resp.tx_hash;
}
bool test_payment_ids_generation(tools::wallet_rpc_server& custody_wlt_rpc)
{
//check make_integrated_address/split_integrated_address
//check auto generated payment_id
pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request req = AUTO_VAL_INIT(req);
pre_hf4_api::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response resp = AUTO_VAL_INIT(resp);
bool r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
//custody_wlt_rpc.handle_http_request()
pre_hf4_api::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request req2 = AUTO_VAL_INIT(req2);
req2.integrated_address = resp.integrated_address;
pre_hf4_api::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response resp2 = AUTO_VAL_INIT(resp2);
r = invoke_text_json_for_rpc(custody_wlt_rpc, "split_integrated_address", req2, resp2);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
CHECK_AND_ASSERT_MES(resp2.payment_id == resp.payment_id, false, "generated paymentids missmatched");
//check manually set payment_id
req.payment_id = resp.payment_id;
r = invoke_text_json_for_rpc(custody_wlt_rpc, "make_integrated_address", req, resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
//custody_wlt_rpc.handle_http_request()
req2.integrated_address = resp.integrated_address;
r = invoke_text_json_for_rpc(custody_wlt_rpc, "split_integrated_address", req2, resp2);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
CHECK_AND_ASSERT_MES(resp2.payment_id == req.payment_id, false, "generated paymentids missmatched");
return true;
}
bool wallet_rpc_exchange_suite::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
account_base alice_acc, bob_acc, carol_acc, custody_acc;
alice_acc.generate();
bob_acc.generate();
carol_acc.generate();
custody_acc.generate();
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, alice_acc);
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, bob_acc);
std::shared_ptr<tools::wallet2> carol_wlt = init_playtime_test_wallet(events, c, carol_acc);
std::shared_ptr<tools::wallet2> custody_wlt = init_playtime_test_wallet(events, c, custody_acc);
r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, 3);
r = mine_next_pow_blocks_in_playtime(bob_wlt->get_account().get_public_address(), c, 3);
r = mine_next_pow_blocks_in_playtime(carol_wlt->get_account().get_public_address(), c, 3);
//r = mine_next_pow_blocks_in_playtime(custody_wlt->get_account().get_public_address(), c, 3);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// wallet RPC server
tools::wallet_rpc_server custody_wlt_rpc(custody_wlt);
r = test_payment_ids_generation(custody_wlt_rpc);
CHECK_AND_ASSERT_MES(r, false, "test_payment_ids_generation() failed ");
//======================================================================
std::string alice_payment_id = gen_payment_id(custody_wlt_rpc);
std::string bob_payment_id = gen_payment_id(custody_wlt_rpc);
std::string carol_payment_id = gen_payment_id(custody_wlt_rpc);
// generate payment id's for each wallet and deposit
custody_wlt->refresh();
alice_wlt->refresh();
bob_wlt->refresh();
carol_wlt->refresh();
#define TRANSFER_AMOUNT COIN / 10
std::string alice_tx1 = transfer_(alice_wlt, get_integr_addr(custody_wlt_rpc, alice_payment_id), TRANSFER_AMOUNT);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
std::string bob_tx1 = transfer_(bob_wlt, get_integr_addr(custody_wlt_rpc, bob_payment_id), TRANSFER_AMOUNT);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
std::string bob_tx2 = transfer_(bob_wlt, get_integr_addr(custody_wlt_rpc, bob_payment_id), TRANSFER_AMOUNT);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
std::string carol_tx1 = transfer_(carol_wlt, get_integr_addr(custody_wlt_rpc, carol_payment_id), TRANSFER_AMOUNT);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
std::string carol_tx2 = transfer_(carol_wlt, get_integr_addr(custody_wlt_rpc, carol_payment_id), TRANSFER_AMOUNT);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
std::string carol_tx3 = transfer_(carol_wlt, get_integr_addr(custody_wlt_rpc, carol_payment_id), TRANSFER_AMOUNT);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, 1);
CHECK_AND_ASSERT_MES(alice_tx1.size()
&& bob_tx1.size()
&& bob_tx2.size()
&& carol_tx1.size()
&& carol_tx2.size()
&& carol_tx3.size(),
false, "One of deposit transactions wan't created"
);
r = mine_next_pow_blocks_in_playtime(miner_wlt->get_account().get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
custody_wlt->refresh();
pre_hf4_api::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request req = AUTO_VAL_INIT(req);
req.update_provision_info = true;
req.count = 10;
pre_hf4_api::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response resp = AUTO_VAL_INIT(resp);
r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_recent_txs_and_info", req, resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
#define CHECK_RESPONSE_EQUAL(condition) CHECK_AND_ASSERT_MES((condition), false, "Failed check");
CHECK_RESPONSE_EQUAL(resp.pi.balance == 600000000000);
CHECK_RESPONSE_EQUAL(resp.pi.unlocked_balance == 600000000000);
CHECK_RESPONSE_EQUAL(resp.pi.transfers_count == 6);
CHECK_RESPONSE_EQUAL(resp.total_transfers == 6);
CHECK_RESPONSE_EQUAL(resp.transfers.size() == 6);
CHECK_RESPONSE_EQUAL(resp.transfers[0].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[0].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[0].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[0].payment_id) == carol_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[0].tx_hash) == carol_tx3);
CHECK_RESPONSE_EQUAL(resp.transfers[1].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[1].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[1].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[1].payment_id) == carol_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[1].tx_hash) == carol_tx2);
CHECK_RESPONSE_EQUAL(resp.transfers[2].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[2].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[2].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[2].payment_id) == carol_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[2].tx_hash) == carol_tx1);
CHECK_RESPONSE_EQUAL(resp.transfers[3].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[3].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[3].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[3].payment_id) == bob_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[3].tx_hash) == bob_tx2);
CHECK_RESPONSE_EQUAL(resp.transfers[4].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[4].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[4].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[4].payment_id) == bob_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[4].tx_hash) == bob_tx1);
CHECK_RESPONSE_EQUAL(resp.transfers[5].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[5].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[5].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[5].payment_id) == alice_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[5].tx_hash) == alice_tx1);
req.count = 10;
req.offset = 2;
r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_recent_txs_and_info", req, resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
CHECK_RESPONSE_EQUAL(resp.pi.balance == 600000000000);
CHECK_RESPONSE_EQUAL(resp.pi.unlocked_balance == 600000000000);
CHECK_RESPONSE_EQUAL(resp.pi.transfers_count == 6);
CHECK_RESPONSE_EQUAL(resp.total_transfers == 6);
CHECK_RESPONSE_EQUAL(resp.transfers.size() == 4);
CHECK_RESPONSE_EQUAL(resp.transfers[0].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[0].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[0].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[0].payment_id) == carol_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[0].tx_hash) == carol_tx1);
CHECK_RESPONSE_EQUAL(resp.transfers[1].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[1].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[1].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[1].payment_id) == bob_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[1].tx_hash) == bob_tx2);
CHECK_RESPONSE_EQUAL(resp.transfers[2].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[2].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[2].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[2].payment_id) == bob_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[2].tx_hash) == bob_tx1);
CHECK_RESPONSE_EQUAL(resp.transfers[3].comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(resp.transfers[3].amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(resp.transfers[3].is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(resp.transfers[3].payment_id) == alice_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(resp.transfers[3].tx_hash) == alice_tx1);
//getbalance
pre_hf4_api::COMMAND_RPC_GET_BALANCE::request gb_req = AUTO_VAL_INIT(gb_req);
pre_hf4_api::COMMAND_RPC_GET_BALANCE::response gb_resp = AUTO_VAL_INIT(gb_resp);
r = invoke_text_json_for_rpc(custody_wlt_rpc, "getbalance", gb_req, gb_resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
CHECK_RESPONSE_EQUAL(gb_resp.balance == 600000000000);
CHECK_RESPONSE_EQUAL(gb_resp.unlocked_balance == 600000000000);
//get_wallet_info
pre_hf4_api::COMMAND_RPC_GET_WALLET_INFO::request gwi_req = AUTO_VAL_INIT(gwi_req);
pre_hf4_api::COMMAND_RPC_GET_WALLET_INFO::response gwi_resp = AUTO_VAL_INIT(gwi_resp);
r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_wallet_info", gwi_req, gwi_resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
CHECK_RESPONSE_EQUAL(gwi_resp.current_height == 35);
CHECK_RESPONSE_EQUAL(gwi_resp.transfer_entries_count == 6);
CHECK_RESPONSE_EQUAL(gwi_resp.transfers_count == 6);
CHECK_RESPONSE_EQUAL(gwi_resp.address == custody_wlt->get_account().get_public_address_str());
//search_for_transactions
pre_hf4_api::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::request st_req = AUTO_VAL_INIT(st_req);
st_req.filter_by_height = false;
st_req.in = true;
st_req.out = true;
st_req.pool = true;
st_req.tx_id = resp.transfers[1].tx_hash; //bob_tx2
pre_hf4_api::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS::response st_resp = AUTO_VAL_INIT(st_resp);
r = invoke_text_json_for_rpc(custody_wlt_rpc, "search_for_transactions", st_req, st_resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
//TODO: add more cases for search transaction in pool, in and out
CHECK_RESPONSE_EQUAL(st_resp.in.size() == 1);
CHECK_RESPONSE_EQUAL(st_resp.in.begin()->comment == TRANSFER_COMMENT);
CHECK_RESPONSE_EQUAL(st_resp.in.begin()->amount == TRANSFER_AMOUNT);
CHECK_RESPONSE_EQUAL(st_resp.in.begin()->is_income == true);
CHECK_RESPONSE_EQUAL(epee::string_tools::buff_to_hex_nodelimer(st_resp.in.begin()->payment_id) == bob_payment_id);
CHECK_RESPONSE_EQUAL(boost::lexical_cast<std::string>(st_resp.in.begin()->tx_hash) == bob_tx2);
//get_payments
pre_hf4_api::COMMAND_RPC_GET_PAYMENTS::request gps_req = AUTO_VAL_INIT(gps_req);
gps_req.payment_id = carol_payment_id;
pre_hf4_api::COMMAND_RPC_GET_PAYMENTS::response gps_resp = AUTO_VAL_INIT(gps_resp);
r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_payments", gps_req, gps_resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
{
//sort by block_height to have deterministic order
gps_resp.payments.sort([&](const pre_hf4_api::payment_details& a, const pre_hf4_api::payment_details& b) {return a.block_height < b.block_height; });
CHECK_RESPONSE_EQUAL(gps_resp.payments.size() == 3);
auto it = gps_resp.payments.begin();
CHECK_RESPONSE_EQUAL(it->amount == 100000000000);
CHECK_RESPONSE_EQUAL(it->payment_id == carol_payment_id);
CHECK_RESPONSE_EQUAL(it->block_height == 23);
it++;
CHECK_RESPONSE_EQUAL(it->amount == 100000000000);
CHECK_RESPONSE_EQUAL(it->payment_id == carol_payment_id);
CHECK_RESPONSE_EQUAL(it->block_height == 24);
it++;
CHECK_RESPONSE_EQUAL(it->amount == 100000000000);
CHECK_RESPONSE_EQUAL(it->payment_id == carol_payment_id);
CHECK_RESPONSE_EQUAL(it->block_height == 25);
}
//get_bulk_payments
pre_hf4_api::COMMAND_RPC_GET_BULK_PAYMENTS::request gbps_req = AUTO_VAL_INIT(gbps_req);
gbps_req.payment_ids.push_back(bob_payment_id);
gbps_req.payment_ids.push_back(alice_payment_id);
pre_hf4_api::COMMAND_RPC_GET_BULK_PAYMENTS::response gbps_resp = AUTO_VAL_INIT(gbps_resp);
r = invoke_text_json_for_rpc(custody_wlt_rpc, "get_bulk_payments", gbps_req, gbps_resp);
CHECK_AND_ASSERT_MES(r, false, "failed to call");
{
//sort by block_height to have deterministic order
gbps_resp.payments.sort([&](const pre_hf4_api::payment_details& a, const pre_hf4_api::payment_details& b) {return a.block_height < b.block_height; });
CHECK_RESPONSE_EQUAL(gbps_resp.payments.size() == 3);
auto it = gbps_resp.payments.begin();
CHECK_RESPONSE_EQUAL(it->amount == 100000000000);
CHECK_RESPONSE_EQUAL(it->payment_id == alice_payment_id);
CHECK_RESPONSE_EQUAL(it->block_height == 20);
it++;
CHECK_RESPONSE_EQUAL(it->amount == 100000000000);
CHECK_RESPONSE_EQUAL(it->payment_id == bob_payment_id);
CHECK_RESPONSE_EQUAL(it->block_height == 21);
it++;
CHECK_RESPONSE_EQUAL(it->amount == 100000000000);
CHECK_RESPONSE_EQUAL(it->payment_id == bob_payment_id);
CHECK_RESPONSE_EQUAL(it->block_height == 22);
}
return true;
}

View file

@ -28,3 +28,16 @@ struct wallet_rpc_transfer : public wallet_test
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
/*
Tests to make sure api for exchanges didn't change after HF4(Zarcanum)
testing api: get_recent_txs_and_info, make_integrated_address,
getbalance, get_wallet_info, get_transfer_by_txid,
*/
struct wallet_rpc_exchange_suite : public wallet_test
{
wallet_rpc_exchange_suite();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};

View file

@ -0,0 +1,431 @@
// Copyright (c) 2014-2024 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
namespace pre_hf4_api
{
struct COMMAND_RPC_MAKE_INTEGRATED_ADDRESS
{
struct request
{
std::string payment_id; // hex-encoded
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payment_id)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string integrated_address;
std::string payment_id; // hex-encoded
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(integrated_address)
KV_SERIALIZE(payment_id)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS
{
struct request
{
std::string integrated_address;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(integrated_address)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string standard_address;
std::string payment_id; // hex-encoded
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(standard_address)
KV_SERIALIZE(payment_id)
END_KV_SERIALIZE_MAP()
};
};
struct transfer_destination
{
uint64_t amount;
std::string address;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE(address)
END_KV_SERIALIZE_MAP()
};
struct tx_service_attachment
{
std::string service_id; //string identifying service which addressed this attachment
std::string instruction; //string identifying specific instructions for service/way to interpret data
std::string body; //any data identifying service, options etc
std::vector<crypto::public_key> security; //some of commands need proof of owner
uint8_t flags; //special flags (ex: TX_SERVICE_ATTACHMENT_ENCRYPT_BODY), see below
BEGIN_SERIALIZE()
FIELD(service_id)
FIELD(instruction)
FIELD(body)
FIELD(security)
FIELD(flags)
END_SERIALIZE()
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(service_id)
KV_SERIALIZE(instruction)
KV_SERIALIZE_BLOB_AS_HEX_STRING(body)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(security)
KV_SERIALIZE(flags)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_TRANSFER
{
struct request
{
std::list<transfer_destination> destinations;
uint64_t fee;
uint64_t mixin;
//uint64_t unlock_time;
std::string payment_id; // hex-encoded
std::string comment;
bool push_payer;
bool hide_receiver;
std::vector<currency::tx_service_attachment> service_entries;
bool service_entries_permanent;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(destinations)
KV_SERIALIZE(fee)
KV_SERIALIZE(mixin)
KV_SERIALIZE(payment_id)
KV_SERIALIZE(comment)
KV_SERIALIZE(push_payer)
KV_SERIALIZE(hide_receiver)
KV_SERIALIZE(service_entries)
KV_SERIALIZE(service_entries_permanent)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string tx_hash;
std::string tx_unsigned_hex; // for cold-signing process
uint64_t tx_size;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(tx_unsigned_hex)
KV_SERIALIZE(tx_size)
END_KV_SERIALIZE_MAP()
};
};
struct wallet_transfer_info_details
{
std::list<uint64_t> rcv;
std::list<uint64_t> spn;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(rcv)
KV_SERIALIZE(spn)
END_KV_SERIALIZE_MAP()
};
struct wallet_transfer_info
{
uint64_t amount;
uint64_t timestamp;
crypto::hash tx_hash;
uint64_t height; //if height == 0 then tx is unconfirmed
uint64_t unlock_time;
uint32_t tx_blob_size;
std::string payment_id;
std::vector<std::string> remote_addresses; //optional
std::vector<std::string> recipients_aliases; //optional
std::string comment;
bool is_income;
bool is_service;
bool is_mixing;
bool is_mining;
uint64_t tx_type;
wallet_transfer_info_details td;
std::vector<tx_service_attachment> service_entries;
//not included in streaming serialization
uint64_t fee;
bool show_sender;
//std::vector<escrow_contract_details> contract; //not traxking this part
uint16_t extra_flags;
uint64_t transfer_internal_index;
//not included in kv serialization map
currency::transaction tx;
std::vector<uint64_t> selected_indicies;
std::list<bc_services::offers_attachment_t> marketplace_entries;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE_POD_AS_HEX_STRING(tx_hash)
KV_SERIALIZE(height)
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(tx_blob_size)
KV_SERIALIZE_BLOB_AS_HEX_STRING(payment_id)
KV_SERIALIZE(remote_addresses)
KV_SERIALIZE(recipients_aliases)
KV_SERIALIZE(comment)
KV_SERIALIZE(is_income)
KV_SERIALIZE(timestamp)
KV_SERIALIZE(td)
KV_SERIALIZE(fee)
KV_SERIALIZE(is_service)
KV_SERIALIZE(is_mixing)
KV_SERIALIZE(is_mining)
KV_SERIALIZE(tx_type)
KV_SERIALIZE(show_sender)
//KV_SERIALIZE(contract)
KV_SERIALIZE(service_entries)
KV_SERIALIZE(transfer_internal_index)
END_KV_SERIALIZE_MAP()
};
struct wallet_provision_info
{
uint64_t transfers_count;
uint64_t transfer_entries_count;
uint64_t balance;
uint64_t unlocked_balance;
uint64_t curent_height;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(transfers_count)
KV_SERIALIZE(transfer_entries_count)
KV_SERIALIZE(balance)
KV_SERIALIZE(unlocked_balance)
KV_SERIALIZE(curent_height)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_GET_RECENT_TXS_AND_INFO
{
struct request
{
/*
if offset is 0, then GET_RECENT_TXS_AND_INFO return
unconfirmed transactions as the first first items of "transfers",
this unconfirmed transactions is not counted regarding "count" parameter
*/
uint64_t offset;
uint64_t count;
/*
need_to_get_info - should backend re-calculate balance(could be relatively heavy,
and not needed when getting long tx history with multiple calls
of GET_RECENT_TXS_AND_INFO with offsets)
*/
bool update_provision_info;
bool exclude_mining_txs;
bool exclude_unconfirmed;
std::string order; // "FROM_BEGIN_TO_END" or "FROM_END_TO_BEGIN"
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(offset)
KV_SERIALIZE(count)
KV_SERIALIZE(update_provision_info)
KV_SERIALIZE(exclude_mining_txs)
KV_SERIALIZE(exclude_unconfirmed)
KV_SERIALIZE(order)
END_KV_SERIALIZE_MAP()
};
struct response
{
wallet_provision_info pi;
std::vector<wallet_transfer_info> transfers;
uint64_t total_transfers;
uint64_t last_item_index;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(pi)
KV_SERIALIZE(transfers)
KV_SERIALIZE(total_transfers)
KV_SERIALIZE(last_item_index)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_GET_BALANCE
{
struct request
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
struct response
{
uint64_t balance;
uint64_t unlocked_balance;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(balance)
KV_SERIALIZE(unlocked_balance)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_GET_WALLET_INFO
{
struct request
{
BEGIN_KV_SERIALIZE_MAP()
END_KV_SERIALIZE_MAP()
};
struct response
{
std::string address;
std::string path;
uint64_t transfers_count;
uint64_t transfer_entries_count;
bool is_whatch_only;
std::vector<std::string> utxo_distribution;
uint64_t current_height;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(path)
KV_SERIALIZE(transfers_count)
KV_SERIALIZE(transfer_entries_count)
KV_SERIALIZE(is_whatch_only)
KV_SERIALIZE(utxo_distribution)
KV_SERIALIZE(current_height)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_SEARCH_FOR_TRANSACTIONS
{
struct request
{
crypto::hash tx_id;
bool in;
bool out;
//bool pending;
//bool failed;
bool pool;
bool filter_by_height;
uint64_t min_height;
uint64_t max_height;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(tx_id)
KV_SERIALIZE(in)
KV_SERIALIZE(out)
//KV_SERIALIZE(pending)
//KV_SERIALIZE(failed)
KV_SERIALIZE(pool)
KV_SERIALIZE(filter_by_height)
KV_SERIALIZE(min_height)
KV_SERIALIZE(max_height)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::list<wallet_transfer_info> in;
std::list<wallet_transfer_info> out;
//std::list<wallet_transfer_info> pending;
//std::list<wallet_transfer_info> failed;
std::list<wallet_transfer_info> pool;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(in)
KV_SERIALIZE(out)
//KV_SERIALIZE(pending)
//KV_SERIALIZE(failed)
KV_SERIALIZE(pool)
END_KV_SERIALIZE_MAP()
};
};
struct payment_details
{
std::string payment_id;
std::string tx_hash;
uint64_t amount;
uint64_t block_height;
uint64_t unlock_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payment_id)
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(amount)
KV_SERIALIZE(block_height)
KV_SERIALIZE(unlock_time)
END_KV_SERIALIZE_MAP()
};
struct COMMAND_RPC_GET_PAYMENTS
{
struct request
{
std::string payment_id; // hex-encoded
bool allow_locked_transactions;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payment_id)
KV_SERIALIZE(allow_locked_transactions)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::list<payment_details> payments;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payments)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_GET_BULK_PAYMENTS
{
struct request
{
std::vector<std::string> payment_ids;
uint64_t min_block_height;
bool allow_locked_transactions;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payment_ids)
KV_SERIALIZE(min_block_height)
KV_SERIALIZE(allow_locked_transactions)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::list<payment_details> payments;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(payments)
END_KV_SERIALIZE_MAP()
};
};
}

View file

@ -65,6 +65,7 @@ bool create_block_template_manually(const currency::block& prev_block, boost::mu
// make things really simple by assuming block size is less than CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE
size_t median_size = 0;
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
bool r = construct_miner_tx(get_block_height(prev_block) + 1,
median_size,
@ -75,6 +76,7 @@ bool create_block_template_manually(const currency::block& prev_block, boost::mu
miner_addr,
result.miner_tx,
block_reward_without_fee,
block_reward,
TRANSACTION_VERSION_PRE_HF4);
CHECK_AND_ASSERT_MES(r, false, "construct_miner_tx failed");

View file

@ -14,8 +14,9 @@ TEST(parse_and_validate_tx_extra, is_correct_parse_and_validate_tx_extra)
currency::account_base acc;
acc.generate();
currency::blobdata b = "dsdsdfsdfsf";
uint64_t block_reward_without_fee = 0;
bool r = currency::construct_miner_tx(0, 0, 10000000000000, 1000, TESTS_DEFAULT_FEE, acc.get_keys().account_address, acc.get_keys().account_address, tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4, b, 1);
uint64_t block_reward_without_fee = 0, block_reward = 0;
bool r = currency::construct_miner_tx(0, 0, 10000000000000, 1000, TESTS_DEFAULT_FEE, acc.get_keys().account_address, acc.get_keys().account_address, tx,
block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, b, 1);
ASSERT_TRUE(r);
crypto::public_key tx_pub_key;
r = currency::parse_and_validate_tx_extra(tx, tx_pub_key);
@ -27,8 +28,9 @@ TEST(parse_and_validate_tx_extra, is_correct_extranonce_too_big)
currency::account_base acc;
acc.generate();
currency::blobdata b(260, 0);
uint64_t block_reward_without_fee = 0;
bool r = currency::construct_miner_tx(0, 0, 10000000000000, 1000, TESTS_DEFAULT_FEE, acc.get_keys().account_address, acc.get_keys().account_address, tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4, b, 1);
uint64_t block_reward_without_fee = 0, block_reward = 0;
bool r = currency::construct_miner_tx(0, 0, 10000000000000, 1000, TESTS_DEFAULT_FEE, acc.get_keys().account_address, acc.get_keys().account_address, tx,
block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, b, 1);
ASSERT_FALSE(r);
}
@ -56,7 +58,7 @@ TEST(parse_and_validate_tx_extra, test_payment_ids)
ASSERT_TRUE(r);
std::string h2;
r = currency::get_payment_id_from_tx(tx.attachment, h2);
r = currency::get_payment_id_from_decrypted_container(tx.attachment, h2);
ASSERT_TRUE(r);
ASSERT_EQ(h, h2);

View file

@ -51,7 +51,7 @@ echo "Building...."
rm -rf build; mkdir -p build/release;
cd build/release;
cmake $testnet_def -D STATIC=true -D ARCH=x86-64 -D BUILD_GUI=TRUE -D OPENSSL_ROOT_DIR="$OPENSSL_ROOT_DIR" -D CMAKE_PREFIX_PATH="$QT_PREFIX_PATH" -D CMAKE_BUILD_TYPE=Release ../..
cmake $testnet_def -D STATIC=true -D ARCH=x86-64 -D DISABLE_TOR=TRUE -D BUILD_GUI=TRUE -D OPENSSL_ROOT_DIR="$OPENSSL_ROOT_DIR" -D CMAKE_PREFIX_PATH="$QT_PREFIX_PATH" -D CMAKE_BUILD_TYPE=Release ../..
if [ $? -ne 0 ]; then
echo "Failed to run cmake"
exit 1