Merge branch 'release'

This commit is contained in:
sowle 2024-05-16 20:35:43 +02:00
commit cc79aa87b3
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
85 changed files with 4232 additions and 1474 deletions

5
.gitmodules vendored
View file

@ -8,4 +8,7 @@
[submodule "contrib/tor-connect"]
path = contrib/tor-connect
url = https://github.com/hyle-team/tor-connect.git
branch = main
branch = main
[submodule "contrib/jwt-cpp"]
path = contrib/jwt-cpp
url = https://github.com/Thalhammer/jwt-cpp.git

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.16)
PROJECT(Zano)
@ -18,6 +18,9 @@ endif()
if(POLICY CMP0043)
cmake_policy(SET CMP0074 NEW)
endif()
if(POLICY CMP0144)
cmake_policy(SET CMP0144 NEW)
endif()
set(CMAKE_CXX_STANDARD 17)
@ -50,7 +53,7 @@ if (UNIX AND NOT APPLE)
else()
# multi configurations for MSVC and XCode
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(CMAKE_CONFIGURATION_TYPES "Release")
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
else()
@ -58,7 +61,7 @@ else()
endif()
endif()
message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}, and built type: ${CMAKE_BUILD_TYPE}")
enable_testing()
set(OPENSSL_USE_STATIC_LIBS TRUE) # link statically
@ -66,7 +69,7 @@ find_package(OpenSSL REQUIRED)
if(APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
endif()
set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers")
@ -74,7 +77,7 @@ set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect su
set(TESTNET FALSE CACHE BOOL "Compile for testnet")
set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon")
include_directories(src contrib/eos_portable_archive contrib contrib/epee/include ${OPENSSL_INCLUDE_DIR} "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib")
include_directories(src contrib/eos_portable_archive contrib contrib/epee/include contrib/jwt-cpp/include ${OPENSSL_INCLUDE_DIR} "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib")
add_definitions(-DSTATICLIB)
@ -122,6 +125,7 @@ if(MSVC)
endforeach()
endif()
include_directories(SYSTEM src/platform/msc)
configure_file(utils/Directory.Build.props.in ${CMAKE_BINARY_DIR}/Directory.Build.props)
else()
set(ARCH default CACHE STRING "CPU to build for: -march value or default")
if("${ARCH}" STREQUAL "default")
@ -225,11 +229,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
set(Boost_LIBRARIES "libboost.a")
#workaround for new XCode 12 policy for builds(now it includes a slice for the "arm64" when builds for simulator)
set(__iphoneos_archs "arm64")
set(__iphonesimulator_archs "x86_64")
#set(__iphonesimulator_archs "arm64,x86_64")
set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "${__iphoneos_archs}")
set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "${__iphoneos_archs}")
set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}")
set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}")
#set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}")
#set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "${__iphonesimulator_archs}")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/")
set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a")
@ -260,8 +264,10 @@ elseif(NOT MSVC)
endif()
if(BUILD_GUI)
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.1) # <-- this is important for Linux GUI build, don't touch it -- sowle
find_package(Qt5Widgets REQUIRED)
find_package(Qt5WebEngineWidgets REQUIRED)
find_package(Qt5WebChannel REQUIRED)
endif()
set(COMMIT_ID_IN_VERSION ON CACHE BOOL "Include commit ID in version")

View file

@ -15,10 +15,10 @@ Be sure to clone the repository properly:\
|--|--|--|--|
| gcc (Linux) | 5.4.0 | 9.4.0 | 12.3.0 |
| llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 |
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2017 (15.9.30) | 2022 (17.7.5) |
| [XCode](https://developer.apple.com/downloads/) (macOS) | 12.3 | 14.3 | 14.3 |
| [CMake](https://cmake.org/download/) | 3.15.5 | 3.22.1 | 3.26.3 |
| [Boost](https://www.boost.org/users/download/) | 1.70 | 1.70 | 1.76 |
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2019 (16.11.34) | 2022 (17.9.5) |
| [XCode](https://developer.apple.com/downloads/) (macOS) | 12.3 | 14.3 | 15.2 |
| [CMake](https://cmake.org/download/) | 3.15.5 | 3.26.3 | 3.29.0 |
| [Boost](https://www.boost.org/users/download/) | 1.70 | 1.70 | 1.84 |
| [OpenSSL](https://www.openssl.org/source/) [(win)](https://slproweb.com/products/Win32OpenSSL.html) | 1.1.1n | 1.1.1w | 1.1.1w |
| [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 5.8.0 | 5.11.2 | 5.15.2 |

View file

@ -14,9 +14,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
message("excluded upnp support for IOS build")
return()
endif()
add_subdirectory(miniupnp/miniupnpc)
set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib")
set_property(TARGET zlibstatic PROPERTY FOLDER "contrib")
set_property(TARGET mdbx PROPERTY FOLDER "contrib")

View file

@ -35,6 +35,7 @@
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <filesystem>
#ifndef MAKE64
#define MAKE64(low,high) ((__int64)(((DWORD)(low)) | ((__int64)((DWORD)(high))) << 32))
@ -561,16 +562,15 @@ namespace file_io_utils
try
{
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
for ( boost::filesystem::directory_iterator itr( epee::string_encoding::utf8_to_wstring(path) ); itr != end_itr; ++itr )
std::filesystem::directory_iterator end_itr; // default construction yields past-the-end
for ( std::filesystem::directory_iterator itr( epee::string_encoding::utf8_to_wstring(path) ); itr != end_itr; ++itr )
{
if ( only_files && boost::filesystem::is_directory(itr->status()) )
if ( only_files && std::filesystem::is_directory(itr->status()) )
{
continue;
}
target_list.push_back(itr->path().filename().string());
}
}
catch(...)

View file

@ -82,6 +82,13 @@ namespace epee
namespace misc_utils
{
template<typename t_type_a, typename t_type_b>
void cast_assign_a_to_b(t_type_a& a, const t_type_b& b)
{
*static_cast<t_type_b*>(&a) = b;
}
template<class _Ty1,
class _Ty2,
class _Ty3>
@ -532,6 +539,92 @@ namespace misc_utils
};
template<typename key, typename expiration_type>
struct expirating_set
{
typedef std::set<key> main_set;
main_set m_set;
std::multimap<expiration_type, typename main_set::iterator> m_expirations;
const main_set& get_set()
{
return m_set;
}
void add(const key& k, const expiration_type& e)
{
auto res = m_set.insert(k);
m_expirations.insert({ e, res.first });
}
void remove_if_expiration_less_than(const expiration_type& e)
{
while(m_expirations.size() && m_expirations.begin()->first < e)
{
m_set.erase(m_expirations.begin()->second);
m_expirations.erase(m_expirations.begin());
}
}
};
template<typename key, typename expiration_type, typename value_type>
struct expirating_map
{
typedef std::map<key, value_type> main_map;
main_map m_map;
std::multimap<expiration_type, typename main_map::iterator> m_expirations;
const main_map& get_map()
{
return m_map;
}
void add(const key& k, const value_type& v, const expiration_type& e)
{
auto res = m_map.insert(k, v);
m_expirations.insert({ e, res.first });
}
void remove_if_expiration_less_than(const expiration_type& e)
{
while (m_expirations.size() && m_expirations.begin()->first < e)
{
m_map.erase(m_expirations.begin()->second);
m_expirations.erase(m_expirations.begin());
}
}
template <class t_archive>
inline void serialize(t_archive& a, const unsigned int ver)
{
std::vector<std::tuple<key, value_type, expiration_type> > items;
if constexpr (t_archive::is_saving::value)
{
for (const auto& item: m_expirations)
{
items.resize(items.size + 1);
std::get<2>(items.back()) = item.first;
std::get<0>(items.back()) = item.second.first;
std::get<1>(items.back()) = item.second.second;
}
}
a & items;
if constexpr (!t_archive::is_saving::value)
{
for (const auto& item : items)
{
this->add(std::get<0>(item), std::get<1>(item), std::get<2>(item));
items.resize(items.size + 1);
std::get<2>(items.back()) = item.first;
std::get<0>(items.back()) = item.second.first;
std::get<1>(items.back()) = item.second.second;
}
}
}
};
} // namespace misc_utils

View file

@ -98,7 +98,7 @@ namespace net_utils
std::string m_transfer_encoding;//"Transfer-Encoding:"
std::string m_content_encoding; //"Content-Encoding:"
std::string m_host; //"Host:"
std::string m_cookie; //"Cookie:"
std::string m_cookie; //"Cookie:"
fields_list m_etc_fields;
void clear()
@ -147,10 +147,10 @@ namespace net_utils
std::string m_http_method_str;
std::string m_full_request_str;
std::string m_replace_html;
std::string m_request_head;
std::string m_request_head;
int m_http_ver_hi;
int m_http_ver_lo;
bool m_have_to_block;
bool m_have_to_block;
http_header_info m_header_info;
uri_content m_uri_content;
size_t m_full_request_buf_size;
@ -166,11 +166,11 @@ namespace net_utils
struct http_response_info
{
int m_response_code;
std::string m_response_comment;
int m_response_code;
std::string m_response_comment;
fields_list m_additional_fields;
std::string m_body;
std::string m_mime_tipe;
std::string m_body;
std::string m_mime_tipe;
http_header_info m_header_info;
int m_http_ver_hi;// OUT paramter only
int m_http_ver_lo;// OUT paramter only

View file

@ -30,133 +30,11 @@
#include "storages/portable_storage_template_helper.h"
#include "http_base.h"
#include "net/net_utils_base.h"
#include "storages/portable_storage_extended_for_doc.h"
template<typename typename_t>
typename_t get_documentation_json_struct()
{
return AUTO_VAL_INIT_T(typename_t);
}
template<typename request_t, typename response_t>
bool auto_doc_t(const std::string& prefix_name, std::string& generate_reference)
{
if (!generate_reference.size()) return true;
request_t req = get_documentation_json_struct<request_t>();
response_t res = get_documentation_json_struct<response_t>();
std::stringstream ss;
ss << prefix_name << ENDL
<< "REQUEST: " << ENDL << epee::serialization::store_t_to_json(req) << ENDL << "--------------------------------" << ENDL
<< "RESPONSE: " << ENDL << epee::serialization::store_t_to_json(res) << ENDL << "################################" << ENDL;
generate_reference += ss.str();
return true;
}
template<typename command_type_t>
bool auto_doc(const std::string& prefix_name, std::string& generate_reference)
{
return auto_doc_t<typename command_type_t::request, typename command_type_t::response>(prefix_name, generate_reference);
}
namespace epee {
namespace net_utils {
namespace http {
struct i_chain_handler
{
virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info,
epee::net_utils::connection_context_base& m_conn_context, bool& call_found, std::string& generate_reference) = 0;
};
}
}
}
#define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response, \
context_type& m_conn_context) \
{\
response.m_response_code = 200; \
response.m_response_comment = "Ok"; \
std::string reference_stub; \
bool call_found = false; \
if(!handle_http_request_map(query_info, response, m_conn_context, call_found, reference_stub) && response.m_response_code == 200) \
{ response.m_response_code = 500; response.m_response_comment = "Internal Server Error"; return true; } \
if (!call_found) \
{ response.m_response_code = 404; response.m_response_comment = "Not Found"; return true; } \
return true; \
}
#define BEGIN_URI_MAP2() template<class t_context> bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response_info, \
t_context& m_conn_context, bool& call_found, std::string& generate_reference) { \
call_found = false; \
if(false) return true; //just a stub to have "else if"
#define BEGIN_URI_MAP2_VIRTUAL() virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response_info, \
epee::net_utils::connection_context_base& m_conn_context, bool& call_found, std::string& generate_reference) { \
call_found = false; \
if(false) return true; //just a stub to have "else if"
#define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, m_conn_context);
#define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
#define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) \
else if(auto_doc<command_type>(s_pattern "[JSON]", generate_reference) && query_info.m_URI == s_pattern) \
{ \
call_found = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
bool res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
CHECK_AND_ASSERT_MES(res, false, "Failed to parse json: \r\n" << query_info.m_body); \
uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
boost::value_initialized<command_type::response> resp;\
res = callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), m_conn_context); \
CHECK_AND_ASSERT_MES(res, false, "Failed to call " << #callback_f << "() while handling " << s_pattern); \
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
epee::serialization::store_t_to_json(static_cast<command_type::response&>(resp), response_info.m_body); \
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
response_info.m_mime_tipe = "application/json"; \
response_info.m_header_info.m_content_type = " application/json"; \
LOG_PRINT("[HTTP/JSON][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
}
#define MAP_URI_AUTO_BIN2(s_pattern, callback_f, command_type) \
else if(auto_doc<command_type>(s_pattern "[BIN]", generate_reference) && query_info.m_URI == s_pattern) \
{ \
call_found = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
bool res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), query_info.m_body); \
CHECK_AND_ASSERT_MES(res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \
uint64_t ticks1 = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::response> resp;\
res = callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), m_conn_context); \
CHECK_AND_ASSERT_MES(res, false, "Failed to call " << #callback_f << "() while handling " << s_pattern); \
uint64_t ticks2 = misc_utils::get_tick_count(); \
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), response_info.m_body); \
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
response_info.m_mime_tipe = " application/octet-stream"; \
response_info.m_header_info.m_content_type = " application/octet-stream"; \
LOG_PRINT( "[HTTP/BIN][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
}
#define CHAIN_TO_PHANDLER(pi_chain_handler) else if (pi_chain_handler && pi_chain_handler->handle_http_request_map(query_info, response_info, m_conn_context, call_found, generate_reference) && call_found) { return true;}
#define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);call_found = true;}
#define END_URI_MAP2() return true;}
namespace epee
namespace epee
{
namespace json_rpc
{
@ -169,7 +47,7 @@ namespace epee
t_param params;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(jsonrpc)
KV_SERIALIZE(jsonrpc) DOC_DSCR("") DOC_EXMP("2.0") DOC_END
KV_SERIALIZE(id)
KV_SERIALIZE(method)
KV_SERIALIZE(params)
@ -185,7 +63,7 @@ namespace epee
KV_SERIALIZE(message)
END_KV_SERIALIZE_MAP()
};
struct dummy_error
{
BEGIN_KV_SERIALIZE_MAP()
@ -220,7 +98,7 @@ namespace epee
t_param result;
epee::serialization::storage_entry id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(jsonrpc)
KV_SERIALIZE(jsonrpc) DOC_DSCR("") DOC_EXMP("2.0") DOC_END
KV_SERIALIZE(id)
KV_SERIALIZE(result)
END_KV_SERIALIZE_MAP()
@ -245,20 +123,270 @@ namespace epee
}
}
template<typename command_type_t>
struct json_command_type_t
template<typename typename_t>
typename_t get_documentation_json_struct()
{
typedef typename epee::json_rpc::request<typename command_type_t::request> request;
typedef typename epee::json_rpc::request<typename command_type_t::response> response;
return AUTO_VAL_INIT_T(typename_t);
}
struct documentation_entry
{
std::string uri;
bool is_binary = false; //if not - then it's JSON
std::string json_method_name;
std::string request_json_example;
std::string request_json_descriptions;
std::string response_json_example;
std::string response_json_descriptions;
std::string method_general_decription;
};
#define JSON_RPC_REFERENCE_MARKER "JSON_RPC"
struct documentation
{
bool do_generate_documentation = false;
std::list<documentation_entry> entries;
};
// Primary template
template<typename T>
struct has_static_member_description {
private:
// SFINAE test function
template<typename U>
static auto test(int) -> decltype(U::description, std::true_type{});
// Fallback function
template<typename>
static auto test(...) -> std::false_type;
public:
// Member constant indicating whether T has a static member
static constexpr bool value = decltype(test<T>(0))::value;
};
#define BEGIN_JSON_RPC_MAP(uri) else if(query_info.m_URI == JSON_RPC_REFERENCE_MARKER || query_info.m_URI == uri) \
template <typename T>
const char* get_command_description()
{
if constexpr (has_static_member_description<T>::value)
{
return T::description;
}
else
{
return "NO DESCRIPTION";
}
}
template <typename T>
void f(T) {} // Definition #2
// Base template
template<typename T>
struct is_std_simple_container : std::false_type {};
// Specializations for each container
template<typename T, typename Alloc>
struct is_std_simple_container<std::vector<T, Alloc>> : std::true_type {};
template<typename T, typename Alloc>
struct is_std_simple_container<std::deque<T, Alloc>> : std::true_type {};
template<typename T, typename Alloc>
struct is_std_simple_container<std::list<T, Alloc>> : std::true_type {};
template<typename T, std::size_t N>
struct is_std_simple_container<std::array<T, N>> : std::true_type {};
template<typename command_type_t, bool is_json_rpc_method>
bool auto_doc(const std::string& uri, const std::string& method, bool is_json, documentation& docs)
{
if (!docs.do_generate_documentation) return true;
docs.entries.resize(docs.entries.size()+1);
docs.entries.back().is_binary = !is_json;
docs.entries.back().uri = uri;
docs.entries.back().json_method_name = method;
docs.entries.back().method_general_decription = get_command_description<command_type_t>();
if constexpr (is_json_rpc_method)
{
//json rpc-like call
typedef typename epee::json_rpc::request<typename command_type_t::request> request_t;
typedef typename epee::json_rpc::response<typename command_type_t::response, typename epee::json_rpc::dummy_error> response_t;
request_t req = AUTO_VAL_INIT(req); //get_documentation_json_struct<request_t>();
if constexpr (is_std_simple_container<typename command_type_t::request>::value)
{
req.params.resize(1);
}
response_t res = AUTO_VAL_INIT(res);
if constexpr (is_std_simple_container<typename command_type_t::response>::value)
{
req.result.resize(1);
}
req.method = method;
epee::serialization::portable_storage_extended_doc ps;
req.store(ps, nullptr);
ps.dump_as_json(docs.entries.back().request_json_example);
ps.dump_as_decriptions(docs.entries.back().request_json_descriptions);
epee::serialization::portable_storage_extended_doc ps_res;
res.store(ps_res, nullptr);
ps_res.dump_as_json(docs.entries.back().response_json_example);
ps_res.dump_as_decriptions(docs.entries.back().response_json_descriptions);
}
else
{
//json/bin uri/based
typedef typename command_type_t::request request_t;
typedef typename command_type_t::response response_t;
request_t req = AUTO_VAL_INIT(req); //get_documentation_json_struct<request_t>();
response_t res = AUTO_VAL_INIT(res); //get_documentation_json_struct<response_t>();
epee::serialization::portable_storage_extended_doc ps;
req.store(ps, nullptr);
ps.dump_as_json(docs.entries.back().request_json_example);
ps.dump_as_decriptions(docs.entries.back().request_json_descriptions);
epee::serialization::portable_storage_extended_doc ps_res;
res.store(ps_res, nullptr);
ps_res.dump_as_json(docs.entries.back().response_json_example);
ps_res.dump_as_decriptions(docs.entries.back().response_json_descriptions);
}
// std::stringstream ss;
// ss << prefix_name << ENDL
// << "REQUEST: " << ENDL << req_str << ENDL << req_str_descr << "--------------------------------" << ENDL
// << "RESPONSE: " << ENDL << res_str << ENDL << res_str_descr << "################################" << ENDL;
// generate_reference += ss.str();
return true;
//return auto_doc_t<typename command_type_t::request, typename command_type_t::response>(prefix_name, generate_reference);
}
namespace epee {
namespace net_utils {
namespace http {
struct i_chain_handler
{
virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info,
epee::net_utils::connection_context_base& m_conn_context, bool& call_found, documentation& docs = epee::net_utils::http::i_chain_handler::m_empty_documentation) = 0;
static inline documentation m_empty_documentation;
};
}
}
}
#define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response, \
context_type& m_conn_context) \
{\
response.m_response_code = 200; \
response.m_response_comment = "Ok"; \
bool call_found = false; \
if(!handle_http_request_map(query_info, response, m_conn_context, call_found) && response.m_response_code == 200) \
{ response.m_response_code = 500; response.m_response_comment = "Internal Server Error"; return true; } \
if (!call_found) \
{ response.m_response_code = 404; response.m_response_comment = "Not Found"; return true; } \
return true; \
}
#define BEGIN_URI_MAP2() template<class t_context> bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response_info, \
t_context& m_conn_context, bool& call_found, documentation& docs = epee::net_utils::http::i_chain_handler::m_empty_documentation) { \
call_found = false; \
if(false) return true; //just a stub to have "else if"
#define BEGIN_URI_MAP2_VIRTUAL() virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response_info, \
epee::net_utils::connection_context_base& m_conn_context, bool& call_found, documentation& docs = epee::net_utils::http::i_chain_handler::m_empty_documentation) { \
call_found = false; \
if(false) return true; //just a stub to have "else if"
#define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, m_conn_context);
#define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
#define MAP_URI_AUTO_JON2(s_pattern, callback_f, command_type) \
else if(auto_doc<command_type, false>(s_pattern, "", true, docs) && query_info.m_URI == s_pattern) \
{ \
if(query_info.m_URI == JSON_RPC_REFERENCE_MARKER) {generate_reference = "JSON RPC URL: " uri "\n";} \
call_found = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
bool res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
CHECK_AND_ASSERT_MES(res, false, "Failed to parse json: \r\n" << query_info.m_body); \
uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
boost::value_initialized<command_type::response> resp;\
res = callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), m_conn_context); \
CHECK_AND_ASSERT_MES(res, false, "Failed to call " << #callback_f << "() while handling " << s_pattern); \
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
epee::serialization::store_t_to_json(static_cast<command_type::response&>(resp), response_info.m_body); \
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
response_info.m_mime_tipe = "application/json"; \
response_info.m_header_info.m_content_type = " application/json"; \
LOG_PRINT("[HTTP/JSON][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
}
#define MAP_URI_AUTO_BIN2(s_pattern, callback_f, command_type) \
else if(auto_doc<command_type, false>(s_pattern, "", false, docs) && query_info.m_URI == s_pattern) \
{ \
call_found = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
bool res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), query_info.m_body); \
CHECK_AND_ASSERT_MES(res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \
uint64_t ticks1 = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::response> resp;\
res = callback_f(static_cast<command_type::request&>(req), static_cast<command_type::response&>(resp), m_conn_context); \
CHECK_AND_ASSERT_MES(res, false, "Failed to call " << #callback_f << "() while handling " << s_pattern); \
uint64_t ticks2 = misc_utils::get_tick_count(); \
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), response_info.m_body); \
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
response_info.m_mime_tipe = " application/octet-stream"; \
response_info.m_header_info.m_content_type = " application/octet-stream"; \
LOG_PRINT( "[HTTP/BIN][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
}
#define CHAIN_TO_PHANDLER(pi_chain_handler) else if (pi_chain_handler && pi_chain_handler->handle_http_request_map(query_info, response_info, m_conn_context, call_found, docs) && call_found) { return true;}
#define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);call_found = true;}
#define END_URI_MAP2() return true;}
//template<typename command_type_t>
//struct json_command_type_t
//{
// typedef typename epee::json_rpc::request<typename command_type_t::request> request;
// typedef typename epee::json_rpc::request<typename command_type_t::response> response;
//};
//#define JSON_RPC_REFERENCE_MARKER "JSON_RPC"
// if(query_info.m_URI == JSON_RPC_REFERENCE_MARKER) {generate_reference = "JSON RPC URL: " uri "\n";} \
#define BEGIN_JSON_RPC_MAP(uri) else if(docs.do_generate_documentation || query_info.m_URI == uri) \
{ \
const char* current_zone_json_uri = uri;\
LOG_PRINT_L4("[JSON_REQUEST_BODY]: " << ENDL << query_info.m_body); \
uint64_t ticks = epee::misc_utils::get_tick_count(); \
epee::serialization::portable_storage ps; \
@ -317,7 +445,7 @@ struct json_command_type_t
LOG_PRINT( query_info.m_URI << "[" << method_name << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2);
#define MAP_JON_RPC_WE(method_name, callback_f, command_type) \
else if(auto_doc<json_command_type_t<command_type>>("[" method_name "]", generate_reference) && callback_name == method_name) \
else if(auto_doc<command_type, true>(current_zone_json_uri, method_name, true, docs) && callback_name == method_name) \
{ \
call_found = true; \
PREPARE_OBJECTS_FROM_JSON(command_type) \
@ -335,7 +463,7 @@ struct json_command_type_t
}
#define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \
else if(auto_doc<json_command_type_t<command_type>>("[" method_name "]", generate_reference) && callback_name == method_name) \
else if(auto_doc<command_type, true>(current_zone_json_uri, method_name, true, docs) && callback_name == method_name) \
{ \
call_found = true; \
PREPARE_OBJECTS_FROM_JSON(command_type) \
@ -353,7 +481,7 @@ struct json_command_type_t
}
#define MAP_JON_RPC(method_name, callback_f, command_type) \
else if(auto_doc<json_command_type_t<command_type>>(std::string("[") + method_name + "]", generate_reference) && callback_name == method_name) \
else if(auto_doc<command_type, true>(current_zone_json_uri, method_name, true, docs) && callback_name == method_name) \
{ \
call_found = true; \
PREPARE_OBJECTS_FROM_JSON(command_type) \
@ -386,4 +514,51 @@ struct json_command_type_t
return true; \
}
namespace epee
{
template<typename t_rpc_server>
bool generate_doc_as_md_files(const std::string& folder, t_rpc_server& server)
{
LOG_PRINT_L0("Dumping RPC auto-generated documents!");
epee::net_utils::http::http_request_info query_info;
epee::net_utils::http::http_response_info response_info;
epee::net_utils::connection_context_base conn_context;
//std::string generate_reference = std::string("WALLET_RPC_COMMANDS_LIST:\n");
bool call_found = false;
documentation docs;
docs.do_generate_documentation = true;
// query_info.m_URI = JSON_RPC_REFERENCE_MARKER;
query_info.m_body = "{\"jsonrpc\": \"2.0\", \"method\": \"nonexisting_method\", \"params\": {}},";
server.handle_http_request_map(query_info, response_info, conn_context, call_found, docs);
for (const auto& de : docs.entries)
{
std::stringstream ss;
ss << de.method_general_decription << ENDL << ENDL;;
ss << "URL: ```http:://127.0.0.1:11211" << de.uri << "```" << ENDL;
ss << "### Request: " << ENDL << "```json" << ENDL << de.request_json_example << ENDL << "```" << ENDL;
ss << "### Request description: " << ENDL << "```" << ENDL << de.request_json_descriptions << ENDL << "```" << ENDL;
ss << "### Response: " << ENDL << "```json" << ENDL << de.response_json_example << ENDL << "```" << ENDL;
ss << "### Response description: " << ENDL << "```" << ENDL << de.response_json_descriptions << ENDL << "```" << ENDL;
std::string filename = de.json_method_name;
if (!filename.size())
{
filename = de.uri;
if (filename.front() == '/')
filename.erase(filename.begin());
}
filename += ".md";
bool r = epee::file_io_utils::save_string_to_file(folder + "/" + filename, ss.str());
if (!r)
{
LOG_ERROR("Failed to save file " << filename);
return false;
}
}
return true;
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2019, anonimal, <anonimal@zano.org>
// Copyright (c) 2019, anonimal, <anonimal@zano.org>
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//

View file

@ -97,6 +97,40 @@ namespace epee
return epee::string_encoding::base64_decode(a);
}
//basic helpers for pod-to-hex serialization
template<class t_pod_container_type>
std::string transform_t_pod_array_to_hex_str_array(const t_pod_container_type& a)
{
std::string res;
for (const auto& item : a)
{
res += epee::string_tools::pod_to_hex(a) + ", ";
}
if (a.size())
{
res.erase(res.size() - 2);
}
return res;
}
template<class t_pod_container_type>
t_pod_container_type transform_hex_str_array_to_t_pod_array(const std::string& a)
{
std::vector<std::string> pod_items;
boost::split(pod_items, a, boost::is_any_of(", ][\""));
t_pod_container_type res;
for (const auto& item : pod_items)
{
res.resize(res.size() + 1);
typename t_pod_container_type::value_type& pod_val = res.back();
if (!epee::string_tools::hex_to_pod(item, pod_val))
throw std::runtime_error(std::string("Unable to transform \"") + item + "\" to pod type " + typeid(typename t_pod_container_type::value_type).name());
}
return res;
}
//-------------------------------------------------------------------------------------------------------------------
#pragma pack(push, 1)
template<class first_t, class second_t>

View file

@ -32,7 +32,7 @@
#include "keyvalue_helpers.h"
#include "keyvalue_serialization_overloads.h"
namespace epee
{
{
/************************************************************************/
/* Serialize map declarations */
/************************************************************************/
@ -65,13 +65,71 @@ public: \
static bool serialize_map(this_type& this_ref, t_storage& stg, typename t_storage::hsection hparent_section) \
{
#define KV_CAT_(a, b) a ## b
#define KV_CAT(a, b) KV_CAT_(a, b)
#define VARNAME(Var) KV_CAT(Var, __LINE__)
#define KV_MAKE_ALIAS_NAME() VARNAME(alias_tmp_name)
#define KV_MAKE_VAR_NAME() VARNAME(val_tmp_name)
#define KV_SERIALIZE_N(varialble, val_name) \
using KV_MAKE_ALIAS_NAME() [[maybe_unused]] = decltype(this_ref.varialble); \
[[maybe_unused]] const char* KV_MAKE_VAR_NAME() = val_name;\
epee::serialization::selector<is_store>::serialize(this_ref.varialble, stg, hparent_section, val_name);
//#define KV_SERIALIZE_N_DOC(varialble, val_name) \
// using KV_MAKE_ALIAS_NAME() = decltype(this_ref.varialble); \
// epee::serialization::selector<is_store>::serialize(this_ref.varialble, stg, hparent_section, val_name); \
// if constexpr (t_storage::use_descriptions::value) \
// { \
// epee::serialization::selector<is_store>::template serialize_and_doc<KV_MAKE_ALIAS_NAME()>(stg, hparent_section, val_name
#define DOC_DSCR(description) if constexpr (t_storage::use_descriptions::value) \
{ \
epee::serialization::selector<is_store>::template serialize_and_doc<KV_MAKE_ALIAS_NAME()>(stg, hparent_section, KV_MAKE_VAR_NAME(), description
/*
{using var_type = decltype(this_ref.varialble); \
epee::serialization::selector<is_store>::serialize(this_ref.varialble, stg, hparent_section, val_name); \
if constexpr (t_storage::use_descriptions::value) \
{ \
epee::serialization::selector<is_store>::set_descr<var_type>(stg, hparent_section, val_name, description, default = var_type()); \
} \
}
*/
//#define DOC_DSCR(description) , description
#define DOC_EXMP(substitute) , substitute
//#define DOC_EXMP_AUTO_1(arg_1) , KV_MAKE_ALIAS_NAME() (arg_1)
//#define DOC_EXMP_AUTO_2(arg_1, arg_2) , KV_MAKE_ALIAS_NAME() (arg_1, arg_2)
#define DOC_END ); }
#define DOC_EXMP_AUTO(...) , epee::create_t_object<KV_MAKE_ALIAS_NAME() >(__VA_ARGS__)
// Function template to create an object with forwarded constructor arguments
template<typename T, typename... Args>
T create_t_object(Args&&... args) {
return T(std::forward<Args>(args)...);
}
//substitute, description);
//#define DOC_EXAMPLE(substitute) substitute,
//#define DOC_EX(substitute__) var_type(substitute__),
//#define DOC_COMMAND(command_general_description) static const char* explain_yourseflf = command_general_description;
#define KV_SERIALIZE_CUSTOM_N(varialble, stored_type, from_v_to_stored, from_stored_to_v, val_name) \
using KV_MAKE_ALIAS_NAME() [[maybe_unused]] = stored_type; \
[[maybe_unused]] const char* VARNAME(val_tmp_name) = val_name;\
epee::serialization::selector<is_store>::template serialize_custom<stored_type>(this_ref.varialble, stg, hparent_section, val_name, from_v_to_stored, from_stored_to_v);
#define KV_SERIALIZE_EPHEMERAL_N(stored_type, from_v_to_stored, val_name) \
using KV_MAKE_ALIAS_NAME() [[maybe_unused]] = stored_type; \
[[maybe_unused]] const char* VARNAME(val_tmp_name) = val_name;\
epee::serialization::selector<is_store>::template serialize_ephemeral<stored_type>(this_ref, stg, hparent_section, val_name, from_v_to_stored);
@ -91,20 +149,30 @@ public: \
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name)
#define KV_SERIALIZE_CONTAINER_POD_AS_HEX_N(varialble, val_name) \
KV_SERIALIZE_CUSTOM_N(varialble, std::string, epee::transform_t_pod_array_to_hex_str_array<decltype(varialble)>, epee::transform_hex_str_array_to_t_pod_array<decltype(varialble)>, val_name)
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
#define END_KV_SERIALIZE_MAP() return true;}
#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble)
#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
#define KV_SERIALIZE_CUSTOM(varialble, stored_type, from_v_to_stored, from_stored_to_v) KV_SERIALIZE_CUSTOM_N(varialble, stored_type, from_v_to_stored, from_stored_to_v, #varialble)
#define KV_SERIALIZE_POD_AS_HEX_STRING(varialble) KV_SERIALIZE_POD_AS_HEX_STRING_N(varialble, #varialble)
#define KV_SERIALIZE_BLOB_AS_HEX_STRING(varialble) KV_SERIALIZE_BLOB_AS_HEX_STRING_N(varialble, #varialble)
#define KV_SERIALIZE_BLOB_AS_BASE64_STRING(variable) KV_SERIALIZE_BLOB_AS_BASE64_STRING_N(variable, #variable)
#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble)
#define KV_SERIALIZE_DOC(varialble) KV_SERIALIZE_N_DOC( varialble, #varialble)
#define DOC_COMMAND(desciption_text) inline static const char* description = desciption_text;
#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
#define KV_SERIALIZE_CONTAINER_POD_AS_HEX(varialble) KV_SERIALIZE_CONTAINER_POD_AS_HEX_N(varialble, #varialble)
#define KV_SERIALIZE_CUSTOM(varialble, stored_type, from_v_to_stored, from_stored_to_v) KV_SERIALIZE_CUSTOM_N(varialble, stored_type, from_v_to_stored, from_stored_to_v, #varialble)
#define KV_SERIALIZE_POD_AS_HEX_STRING(varialble) KV_SERIALIZE_POD_AS_HEX_STRING_N(varialble, #varialble)
#define KV_SERIALIZE_BLOB_AS_HEX_STRING(varialble) KV_SERIALIZE_BLOB_AS_HEX_STRING_N(varialble, #varialble)
#define KV_SERIALIZE_BLOB_AS_BASE64_STRING(variable) KV_SERIALIZE_BLOB_AS_BASE64_STRING_N(variable, #variable)
#define KV_CHAIN_MAP(variable_obj) epee::namespace_accessor<decltype(this_ref.variable_obj)>::template serialize_map<is_store>(this_ref.variable_obj, stg, hparent_section);

View file

@ -315,9 +315,28 @@ namespace epee
struct selector<true>
{
template<class t_type, class t_storage>
static bool serialize(const t_type& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
static bool serialize(const t_type& d, t_storage& stg, [[maybe_unused]] typename t_storage::hsection hparent_section, [[maybe_unused]] const char* pname)
{
return kv_serialize(d, stg, hparent_section, pname);
//if constexpr (!t_storage::use_descriptions::value)
//{
return kv_serialize(d, stg, hparent_section, pname);
//}
//else
// return false;
}
//const t_type& doc_substitute = t_type(), const std::string& description = std::string()
template<class t_type, class t_storage>
static bool serialize_and_doc(t_storage& stg, typename t_storage::hsection hparent_section, const char* pname, const std::string& description = std::string(), const t_type& doc_substitute = t_type())
{
if constexpr (t_storage::use_descriptions::value)
{
stg.set_entry_description(hparent_section, pname, description);
return kv_serialize(doc_substitute, stg, hparent_section, pname);
}
else
return false;
}
template<class t_type, class t_storage>
@ -478,6 +497,5 @@ namespace epee
return r;
}
}
}

View file

@ -44,15 +44,20 @@ namespace epee
/************************************************************************/
/* */
/************************************************************************/
class portable_storage
template<typename t_section>
class portable_storage_base
{
public:
typedef epee::serialization::hsection hsection;
//typedef epee::serialization::hsection hsection;
using use_descriptions = std::false_type;
typedef t_section* hsection;
typedef epee::serialization::harray harray;
typedef storage_entry meta_entry;
portable_storage(){}
virtual ~portable_storage(){}
portable_storage_base
(){}
virtual ~portable_storage_base
(){}
hsection open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist = false);
template<class t_value>
bool get_value(const std::string& value_name, t_value& val, hsection hparent_section);
@ -63,18 +68,18 @@ namespace epee
//serial access for arrays of values --------------------------------------
//values
template<class t_value>
harray get_first_value(const std::string& value_name, t_value& target, hsection hparent_section);
harray get_first_value(const std::string& value_name, t_value& target, hsection hparent_section);
template<class t_value>
bool get_next_value(harray hval_array, t_value& target);
template<class t_value>
harray insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section);
harray insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section);
template<class t_value>
bool insert_next_value(harray hval_array, const t_value& target);
//sections
harray get_first_section(const std::string& pSectionName, hsection& h_child_section, hsection hparent_section);
bool get_next_section(harray hSecArray, hsection& h_child_section);
harray insert_first_section(const std::string& pSectionName, hsection& hinserted_childsection, hsection hparent_section);
bool insert_next_section(harray hSecArray, hsection& hinserted_childsection);
harray get_first_section(const std::string& pSectionName, hsection& h_child_section, hsection hparent_section);
bool get_next_section(harray hSecArray, hsection& h_child_section);
harray insert_first_section(const std::string& pSectionName, hsection& hinserted_childsection, hsection hparent_section);
bool insert_next_section(harray hSecArray, hsection& hinserted_childsection);
//------------------------------------------------------------------------
//delete entry (section, value or array)
bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr);
@ -83,12 +88,13 @@ namespace epee
bool load_from_binary(const binarybuffer& target);
template<class trace_policy>
bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
bool dump_as_json(std::string& targetObj, size_t indent = 0, end_of_line_t eol = eol_crlf);
bool dump_as_json(std::string& targetObj, size_t indent = 0/*, end_of_line_t eol = eol_crlf*/);
bool load_from_json(const std::string& source);
void set_entry_description(hsection hparent_section, const std::string& name, const std::string& description) {}
template<typename cb_t>
bool enum_entries(hsection hparent_section, cb_t cb);
private:
protected:
section m_root;
hsection get_root_section() {return &m_root;}
storage_entry* find_storage_entry(const std::string& pentry_name, hsection psection);
@ -107,32 +113,36 @@ namespace epee
};
#pragma pack(pop)
};
inline
bool portable_storage::dump_as_json(std::string& buff, size_t indent /* = 0 */, end_of_line_t eol /* = eol_crlf */)
template<typename t_section>
bool portable_storage_base<t_section>::dump_as_json(std::string& buff, size_t indent /* = 0 *//*, end_of_line_t eol *//* = eol_crlf */)
{
TRY_ENTRY();
std::stringstream ss;
epee::serialization::dump_as_json(ss, m_root, indent, eol);
epee::serialization::recursive_visitor<strategy_json>::dump_as_(ss, m_root, indent/*, eol*/);
buff = ss.str();
return true;
CATCH_ENTRY("portable_storage::dump_as_json", false)
CATCH_ENTRY("portable_storage_base<t_section>::dump_as_json", false)
}
inline
bool portable_storage::load_from_json(const std::string& source)
template<typename t_section>
bool portable_storage_base<t_section>::load_from_json(const std::string& source)
{
TRY_ENTRY();
return json::load_from_json(source, *this);
CATCH_ENTRY("portable_storage::load_from_json", false)
CATCH_ENTRY("portable_storage_base<t_section>::load_from_json", false)
}
template<typename t_section>
template<class trace_policy>
bool portable_storage::dump_as_xml(std::string& targetObj, const std::string& root_name)
bool portable_storage_base<t_section>::dump_as_xml(std::string& targetObj, const std::string& root_name)
{
return false;//TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
}
inline
bool portable_storage::store_to_binary(binarybuffer& target)
template<typename t_section>
bool portable_storage_base<t_section>::store_to_binary(binarybuffer& target)
{
TRY_ENTRY();
std::stringstream ss;
@ -144,10 +154,10 @@ namespace epee
pack_entry_to_buff(ss, m_root);
target = ss.str();
return true;
CATCH_ENTRY("portable_storage::store_to_binary", false)
CATCH_ENTRY("portable_storage_base<t_section>::store_to_binary", false)
}
inline
bool portable_storage::load_from_binary(const binarybuffer& source)
template<typename t_section>
bool portable_storage_base<t_section>::load_from_binary(const binarybuffer& source)
{
m_root.m_entries.clear();
if(source.size() < sizeof(storage_block_header))
@ -172,11 +182,11 @@ namespace epee
throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header));
buf_reader.read(m_root);
return true;//TODO:
CATCH_ENTRY("portable_storage::load_from_binary", false);
CATCH_ENTRY("portable_storage_base<t_section>::load_from_binary", false);
}
//---------------------------------------------------------------------------------------------------------------
inline
hsection portable_storage::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist)
template<typename t_section>
typename portable_storage_base<t_section>::hsection portable_storage_base<t_section>::open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist)
{
TRY_ENTRY();
hparent_section = hparent_section ? hparent_section:&m_root;
@ -197,7 +207,7 @@ namespace epee
return nullptr;
}
return &boost::get<section>(*pentry);
CATCH_ENTRY("portable_storage::open_section", nullptr);
CATCH_ENTRY("portable_storage_base<t_section>::open_section", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
template<class to_type>
@ -209,8 +219,9 @@ namespace epee
void operator()(const from_type& v){convert_t(v, m_target);}
};
template<typename t_section>
template<class t_value>
bool portable_storage::get_value(const std::string& value_name, t_value& val, hsection hparent_section)
bool portable_storage_base<t_section>::get_value(const std::string& value_name, t_value& val, hsection hparent_section)
{
BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
//TRY_ENTRY();
@ -222,11 +233,11 @@ namespace epee
get_value_visitor<t_value> gvv(val);
boost::apply_visitor(gvv, *pentry);
return true;
//CATCH_ENTRY("portable_storage::template<>get_value", false);
//CATCH_ENTRY("portable_storage_base<t_section>::template<>get_value", false);
}
//---------------------------------------------------------------------------------------------------------------
inline
bool portable_storage::get_value(const std::string& value_name, storage_entry& val, hsection hparent_section)
template<typename t_section>
bool portable_storage_base<t_section>::get_value(const std::string& value_name, storage_entry& val, hsection hparent_section)
{
//TRY_ENTRY();
if(!hparent_section) hparent_section = &m_root;
@ -236,11 +247,12 @@ namespace epee
val = *pentry;
return true;
//CATCH_ENTRY("portable_storage::template<>get_value", false);
//CATCH_ENTRY("portable_storage_base<t_section>::template<>get_value", false);
}
//---------------------------------------------------------------------------------------------------------------
template<typename t_section>
template<class t_value>
bool portable_storage::set_value(const std::string& value_name, const t_value& v, hsection hparent_section)
bool portable_storage_base<t_section>::set_value(const std::string& value_name, const t_value& v, hsection hparent_section)
{
BOOST_MPL_ASSERT(( boost::mpl::contains<boost::mpl::push_front<storage_entry::types, storage_entry>::type, t_value> ));
TRY_ENTRY();
@ -256,11 +268,11 @@ namespace epee
}
*pentry = storage_entry(v);
return true;
CATCH_ENTRY("portable_storage::template<>set_value", false);
CATCH_ENTRY("portable_storage_base<t_section>::template<>set_value", false);
}
//---------------------------------------------------------------------------------------------------------------
inline
storage_entry* portable_storage::find_storage_entry(const std::string& pentry_name, hsection psection)
template<typename t_section>
storage_entry* portable_storage_base<t_section>::find_storage_entry(const std::string& pentry_name, hsection psection)
{
TRY_ENTRY();
CHECK_AND_ASSERT(psection, nullptr);
@ -269,27 +281,28 @@ namespace epee
return nullptr;
return &it->second;
CATCH_ENTRY("portable_storage::find_storage_entry", nullptr);
CATCH_ENTRY("portable_storage_base<t_section>::find_storage_entry", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
template<typename t_section>
template<class entry_type>
storage_entry* portable_storage::insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry)
storage_entry* portable_storage_base<t_section>::insert_new_entry_get_storage_entry(const std::string& pentry_name, hsection psection, const entry_type& entry)
{
TRY_ENTRY();
CHECK_AND_ASSERT(psection, nullptr);
auto ins_res = psection->m_entries.insert(std::pair<std::string, storage_entry>(pentry_name, entry));
return &ins_res.first->second;
CATCH_ENTRY("portable_storage::insert_new_entry_get_storage_entry", nullptr);
CATCH_ENTRY("portable_storage_base<t_section>::insert_new_entry_get_storage_entry", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
inline
hsection portable_storage::insert_new_section(const std::string& pentry_name, hsection psection)
template<typename t_section>
typename portable_storage_base<t_section>::hsection portable_storage_base<t_section>::insert_new_section(const std::string& pentry_name, hsection psection)
{
TRY_ENTRY();
storage_entry* pse = insert_new_entry_get_storage_entry(pentry_name, psection, section());
if(!pse) return nullptr;
return &boost::get<section>(*pse);
CATCH_ENTRY("portable_storage::insert_new_section", nullptr);
CATCH_ENTRY("portable_storage_base<t_section>::insert_new_section", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
template<class to_type>
@ -308,8 +321,9 @@ namespace epee
}
};
//---------------------------------------------------------------------------------------------------------------
template<typename t_section>
template<class t_value>
harray portable_storage::get_first_value(const std::string& value_name, t_value& target, hsection hparent_section)
harray portable_storage_base<t_section>::get_first_value(const std::string& value_name, t_value& target, hsection hparent_section)
{
BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
//TRY_ENTRY();
@ -325,7 +339,7 @@ namespace epee
if(!boost::apply_visitor(gfv, ar_entry))
return nullptr;
return &ar_entry;
//CATCH_ENTRY("portable_storage::get_first_value", nullptr);
//CATCH_ENTRY("portable_storage_base<t_section>::get_first_value", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
template<class to_type>
@ -344,10 +358,10 @@ namespace epee
return true;
}
};
//---------------------------------------------------------------------------------------------------------------
template<typename t_section>
template<class t_value>
bool portable_storage::get_next_value(harray hval_array, t_value& target)
bool portable_storage_base<t_section>::get_next_value(harray hval_array, t_value& target)
{
BOOST_MPL_ASSERT(( boost::mpl::contains<storage_entry::types, t_value> ));
//TRY_ENTRY();
@ -357,11 +371,12 @@ namespace epee
if(!boost::apply_visitor(gnv, ar_entry))
return false;
return true;
//CATCH_ENTRY("portable_storage::get_next_value", false);
//CATCH_ENTRY("portable_storage_base<t_section>::get_next_value", false);
}
//---------------------------------------------------------------------------------------------------------------
template<typename t_section>
template<class t_value>
harray portable_storage::insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section)
harray portable_storage_base<t_section>::insert_first_value(const std::string& value_name, const t_value& target, hsection hparent_section)
{
TRY_ENTRY();
if(!hparent_section) hparent_section = &m_root;
@ -382,11 +397,12 @@ namespace epee
array_entry_t<t_value>& arr_typed = boost::get<array_entry_t<t_value> >(arr);
arr_typed.insert_first_val(target);
return &arr;
CATCH_ENTRY("portable_storage::insert_first_value", nullptr);
CATCH_ENTRY("portable_storage_base<t_section>::insert_first_value", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
template<typename t_section>
template<typename cb_t>
bool portable_storage::enum_entries(hsection hparent_section, cb_t cb)
bool portable_storage_base<t_section>::enum_entries(hsection hparent_section, cb_t cb)
{
TRY_ENTRY();
if (!hparent_section) hparent_section = &m_root;
@ -396,11 +412,12 @@ namespace epee
break;
}
return true;
CATCH_ENTRY("portable_storage::enum_entries", false);
CATCH_ENTRY("portable_storage_base<t_section>::enum_entries", false);
}
//---------------------------------------------------------------------------------------------------------------
template<typename t_section>
template<class t_value>
bool portable_storage::insert_next_value(harray hval_array, const t_value& target)
bool portable_storage_base<t_section>::insert_next_value(harray hval_array, const t_value& target)
{
TRY_ENTRY();
CHECK_AND_ASSERT(hval_array, false);
@ -411,12 +428,12 @@ namespace epee
array_entry_t<t_value>& arr_typed = boost::get<array_entry_t<t_value> >(*hval_array);
arr_typed.insert_next_value(target);
return true;
CATCH_ENTRY("portable_storage::insert_next_value", false);
CATCH_ENTRY("portable_storage_base<t_section>::insert_next_value", false);
}
//---------------------------------------------------------------------------------------------------------------
//sections
inline
harray portable_storage::get_first_section(const std::string& sec_name, hsection& h_child_section, hsection hparent_section)
template<typename t_section>
harray portable_storage_base<t_section>::get_first_section(const std::string& sec_name, hsection& h_child_section, hsection hparent_section)
{
TRY_ENTRY();
if(!hparent_section) hparent_section = &m_root;
@ -434,11 +451,11 @@ namespace epee
return nullptr;
h_child_section = psec;
return &ar_entry;
CATCH_ENTRY("portable_storage::get_first_section", nullptr);
CATCH_ENTRY("portable_storage_base<t_section>::get_first_section", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
inline
bool portable_storage::get_next_section(harray hsec_array, hsection& h_child_section)
template<typename t_section>
bool portable_storage_base<t_section>::get_next_section(harray hsec_array, hsection& h_child_section)
{
TRY_ENTRY();
CHECK_AND_ASSERT(hsec_array, false);
@ -449,11 +466,11 @@ namespace epee
if(!h_child_section)
return false;
return true;
CATCH_ENTRY("portable_storage::get_next_section", false);
CATCH_ENTRY("portable_storage_base<t_section>::get_next_section", false);
}
//---------------------------------------------------------------------------------------------------------------
inline
harray portable_storage::insert_first_section(const std::string& sec_name, hsection& hinserted_childsection, hsection hparent_section)
template<typename t_section>
harray portable_storage_base<t_section>::insert_first_section(const std::string& sec_name, hsection& hinserted_childsection, hsection hparent_section)
{
TRY_ENTRY();
if(!hparent_section) hparent_section = &m_root;
@ -474,11 +491,11 @@ namespace epee
array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(ar_entry);
hinserted_childsection = &sec_array.insert_first_val(section());
return &ar_entry;
CATCH_ENTRY("portable_storage::insert_first_section", nullptr);
CATCH_ENTRY("portable_storage_base<t_section>::insert_first_section", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
inline
bool portable_storage::insert_next_section(harray hsec_array, hsection& hinserted_childsection)
template<typename t_section>
bool portable_storage_base<t_section>::insert_next_section(harray hsec_array, hsection& hinserted_childsection)
{
TRY_ENTRY();
CHECK_AND_ASSERT(hsec_array, false);
@ -488,8 +505,9 @@ namespace epee
array_entry_t<section>& sec_array = boost::get<array_entry_t<section>>(*hsec_array);
hinserted_childsection = &sec_array.insert_next_value(section());
return true;
CATCH_ENTRY("portable_storage::insert_next_section", false);
CATCH_ENTRY("portable_storage_base<t_section>::insert_next_section", false);
}
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
typedef portable_storage_base<section> portable_storage;
}
}

View file

@ -153,6 +153,7 @@ namespace epee
/************************************************************************/
struct section
{
std::map<std::string, std::string> m_descriptions;
std::map<std::string, storage_entry> m_entries;
};

View file

@ -0,0 +1,67 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
#include "portable_storage.h"
#include "portable_storage_to_description.h"
namespace epee
{
namespace serialization
{
/************************************************************************/
/* */
/************************************************************************/
class portable_storage_extended_doc: public portable_storage
{
public:
using use_descriptions = std::true_type;
void set_entry_description(hsection hparent_section, const std::string& name, const std::string& description)
{
if (!hparent_section)
hparent_section = &m_root;
hparent_section->m_descriptions[name] = description;
}
bool dump_as_decriptions(std::string& buff, size_t indent = 0 , end_of_line_t eol = eol_crlf)
{
TRY_ENTRY();
std::stringstream ss;
recursive_visitor<strategy_descriptin>::dump_as_(ss, m_root, indent);
buff = ss.str();
return true;
CATCH_ENTRY("portable_storage_base<t_section>::dump_as_json", false)
}
};
//---------------------------------------------------------------------------------------------------------------
}
}

View file

@ -56,16 +56,16 @@ namespace epee
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
bool store_t_to_json(const t_struct& str_in, std::string& json_buff, size_t indent = 0, end_of_line_t eol = eol_crlf)
bool store_t_to_json(const t_struct& str_in, std::string& json_buff, size_t indent = 0)
{
portable_storage ps;
str_in.store(ps);
ps.dump_as_json(json_buff, indent, eol);
ps.dump_as_json(json_buff, indent);
return true;
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
std::string store_t_to_json(const t_struct& str_in, size_t indent = 0, end_of_line_t eol = eol_crlf)
std::string store_t_to_json(const t_struct& str_in, size_t indent = 0)
{
std::string json_buff;
store_t_to_json(str_in, json_buff, indent);

View file

@ -0,0 +1,149 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
#include "misc_language.h"
#include "portable_storage_base.h"
namespace epee
{
namespace serialization
{
template <typename t_strategy_layout_strategy>
class recursive_visitor
{
public:
template<class t_stream>
struct array_entry_store_to_json_visitor : public boost::static_visitor<void>
{
t_stream& m_strm;
size_t m_indent;
array_entry_store_to_json_visitor(t_stream& strm, size_t indent)
: m_strm(strm)
, m_indent(indent)
{}
template<class t_type>
void operator()(const array_entry_t<t_type>& a)
{
t_strategy_layout_strategy::handle_array_start(m_strm, m_indent);
if (a.m_array.size())
{
auto last_it = --a.m_array.end();
for (auto it = a.m_array.begin(); it != a.m_array.end(); it++)
{
dump_as_(m_strm, *it, m_indent);
if (it != last_it)
t_strategy_layout_strategy::handle_array_entry_separator(m_strm, m_indent);
}
}
t_strategy_layout_strategy::handle_array_end(m_strm, m_indent);
}
};
template<class t_stream>
struct storage_entry_store_to_json_visitor : public boost::static_visitor<void>
{
t_stream& m_strm;
size_t m_indent;
storage_entry_store_to_json_visitor(t_stream& strm, size_t indent)
: m_strm(strm)
, m_indent(indent)
{}
//section, array_entry
template<class visited_type>
void operator()(const visited_type& v)
{
dump_as_(m_strm, v, m_indent);
}
};
template<class t_stream>
void static dump_as_(t_stream& strm, const array_entry& ae, size_t indent)
{
array_entry_store_to_json_visitor<t_stream> aesv(strm, indent);
boost::apply_visitor(aesv, ae);
}
template<class t_stream>
void static dump_as_(t_stream& strm, const storage_entry& se, size_t indent)
{
storage_entry_store_to_json_visitor<t_stream> sv(strm, indent);
boost::apply_visitor(sv, se);
}
template<class t_stream, class t_type>
void static dump_as_(t_stream& strm, const t_type& v, size_t indent)
{
t_strategy_layout_strategy::handle_value(strm, v, indent);
}
template<class t_stream>
void static dump_as_(t_stream& strm, const section& sec, size_t indent)
{
size_t local_indent = indent + 1;
t_strategy_layout_strategy::handle_obj_begin(strm, indent);
t_strategy_layout_strategy::handle_line_break(strm, indent);
if (sec.m_entries.size())
{
auto it_last = --sec.m_entries.end();
for (auto it = sec.m_entries.begin(); it != sec.m_entries.end(); it++)
{
if constexpr (t_strategy_layout_strategy::use_descriptions::value)
{
std::string descr;
auto it_descr = sec.m_descriptions.find(it->first);
if (it_descr != sec.m_descriptions.end())
descr = it_descr->second;
t_strategy_layout_strategy::handle_print_key(strm, it->first, descr, local_indent);
}
else
{
t_strategy_layout_strategy::handle_print_key(strm, it->first, local_indent);
}
dump_as_(strm, it->second, local_indent);
if (it_last != it)
t_strategy_layout_strategy::handle_section_entry_separator(strm, indent);
t_strategy_layout_strategy::handle_line_break(strm, indent);
}
}
t_strategy_layout_strategy::handle_obj_end(strm, indent);
}
};
}
}

View file

@ -0,0 +1,107 @@
// Copyright (c) 2006-2024, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
#include "misc_language.h"
#include "portable_storage_base.h"
#include "portable_storage_to_.h"
namespace epee
{
namespace serialization
{
class strategy_descriptin
{
public:
using use_descriptions = std::true_type;
inline static const char* eol = get_endline(eol_crlf);
//static const end_of_line_t eol = eol_crlf;
template<class t_stream, class t_type>
static void handle_value(t_stream& strm, const t_type& v, size_t indent)
{}
template<class t_stream>
static void handle_array_start(t_stream& strm, size_t indent)
{
//strm << "[";
}
template<class t_stream>
static void handle_array_end(t_stream& strm, size_t indent)
{
//strm << "]";
}
template<class t_stream>
static void handle_obj_begin(t_stream& strm, size_t indent)
{}
template<class t_stream>
static void handle_obj_end(t_stream& strm, size_t indent)
{}
template<class t_stream>
static void handle_print_key(t_stream& strm, const std::string& key, const std::string& description, size_t indent)
{
if (description.size())
{
const std::string indent_str = make_indent(indent);
strm << indent_str << "\"" << key << "\"" << ": " << description << eol;
}
}
template<class t_stream>
static void handle_print_description(t_stream& strm, const std::string& description, size_t indent)
{
}
template<class t_stream>
static void handle_section_entry_separator(t_stream& strm, size_t indent)
{
//strm << ",";
}
template<class t_stream>
static void handle_array_entry_separator(t_stream& strm, size_t indent)
{
//strm << ",";
}
template<class t_stream>
static void handle_line_break(t_stream& strm, size_t indent)
{
//strm << eol;
}
};
}
}

View file

@ -30,174 +30,121 @@
#include "misc_language.h"
#include "portable_storage_base.h"
#include "portable_storage_to_.h"
namespace epee
{
namespace serialization
{
template<class t_stream>
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const bool& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const double& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream, class t_type>
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, end_of_line_t eol = eol_crlf);
template<class t_stream>
void dump_as_json(t_stream& strm, const section& sec, size_t indent, end_of_line_t eol = eol_crlf);
inline const char* get_endline(end_of_line_t eol)
{
switch (eol)
{
case eol_lf: return "\n";
case eol_cr: return "\r";
case eol_space: return " ";
default: return "\r\n";
}
}
inline std::string make_indent(size_t indent)
{
return std::string(indent*2, ' ');
return std::string(indent * 2, ' ');
}
template<class t_stream>
struct array_entry_store_to_json_visitor: public boost::static_visitor<void>
class strategy_json
{
t_stream& m_strm;
size_t m_indent;
end_of_line_t m_eol;
public:
using use_descriptions = std::false_type;
array_entry_store_to_json_visitor(t_stream& strm, size_t indent, end_of_line_t eol)
: m_strm(strm)
, m_indent(indent)
, m_eol(eol)
{}
template<class t_type>
void operator()(const array_entry_t<t_type>& a)
inline static const char* eol = get_endline(eol_crlf);
//static const end_of_line_t eol = eol_crlf;
template<class t_stream>
static void handle_value(t_stream& strm, const std::string& v, size_t indent)
{
m_strm << "[";
if(a.m_array.size())
{
auto last_it = --a.m_array.end();
for(auto it = a.m_array.begin(); it != a.m_array.end(); it++)
{
dump_as_json(m_strm, *it, m_indent, m_eol);
if(it != last_it)
m_strm << ",";
}
}
m_strm << "]";
strm << "\"" << misc_utils::parse::transform_to_json_escape_sequence(v) << "\"";
}
template<class t_stream>
static void handle_value(t_stream& strm, const int8_t& v, size_t indent)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
static void handle_value(t_stream& strm, const uint8_t& v, size_t indent)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
static void handle_value(t_stream& strm, const bool& v, size_t indent)
{
if (v)
strm << "true";
else
strm << "false";
}
template<class t_stream>
static void handle_value(t_stream& strm, const double& v, size_t indent)
{
boost::io::ios_flags_saver ifs(strm);
strm.precision(8);
strm << std::fixed << v;
}
template<class t_stream, class t_type>
static void handle_value(t_stream& strm, const t_type& v, size_t indent)
{
strm << v;
}
template<class t_stream>
static void handle_array_start(t_stream& strm, size_t indent)
{
strm << "[";
}
template<class t_stream>
static void handle_array_end(t_stream& strm, size_t indent)
{
strm << "]";
}
template<class t_stream>
static void handle_obj_begin(t_stream& strm, size_t indent)
{
strm << "{";
}
template<class t_stream>
static void handle_obj_end(t_stream& strm, size_t indent)
{
strm << "}";
}
template<class t_stream>
static void handle_print_key(t_stream& strm, const std::string& key, size_t indent)
{
const std::string indent_str = make_indent(indent);
strm << indent_str << "\"" << misc_utils::parse::transform_to_json_escape_sequence(key) << "\"" << ": ";
}
template<class t_stream>
static void handle_section_entry_separator(t_stream& strm, size_t indent)
{
strm << ",";
}
template<class t_stream>
static void handle_array_entry_separator(t_stream& strm, size_t indent)
{
strm << ",";
}
template<class t_stream>
static void handle_line_break(t_stream& strm, size_t indent)
{
strm << eol;
}
};
template<class t_stream>
struct storage_entry_store_to_json_visitor: public boost::static_visitor<void>
{
t_stream& m_strm;
size_t m_indent;
end_of_line_t m_eol;
storage_entry_store_to_json_visitor(t_stream& strm, size_t indent, end_of_line_t eol)
: m_strm(strm)
, m_indent(indent)
, m_eol(eol)
{}
//section, array_entry
template<class visited_type>
void operator()(const visited_type& v)
{
dump_as_json(m_strm, v, m_indent, m_eol);
}
};
template<class t_stream>
void dump_as_json(t_stream& strm, const array_entry& ae, size_t indent, end_of_line_t eol)
{
array_entry_store_to_json_visitor<t_stream> aesv(strm, indent, eol);
boost::apply_visitor(aesv, ae);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const storage_entry& se, size_t indent, end_of_line_t eol)
{
storage_entry_store_to_json_visitor<t_stream> sv(strm, indent, eol);
boost::apply_visitor(sv, se);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const std::string& v, size_t indent, end_of_line_t eol)
{
strm << "\"" << misc_utils::parse::transform_to_json_escape_sequence(v) << "\"";
}
template<class t_stream>
void dump_as_json(t_stream& strm, const int8_t& v, size_t indent, end_of_line_t eol)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const uint8_t& v, size_t indent, end_of_line_t eol)
{
strm << static_cast<int32_t>(v);
}
template<class t_stream>
void dump_as_json(t_stream& strm, const bool& v, size_t indent, end_of_line_t eol)
{
if(v)
strm << "true";
else
strm << "false";
}
template<class t_stream>
void dump_as_json(t_stream& strm, const double& v, size_t indent, end_of_line_t eol)
{
boost::io::ios_flags_saver ifs(strm);
strm.precision(8);
strm << std::fixed << v;
}
template<class t_stream, class t_type>
void dump_as_json(t_stream& strm, const t_type& v, size_t indent, end_of_line_t eol)
{
strm << v;
}
template<class t_stream>
void dump_as_json(t_stream& strm, const section& sec, size_t indent, end_of_line_t eol)
{
auto put_eol = [&]() {
switch (eol)
{
case eol_lf: strm << "\n"; break;
case eol_cr: strm << "\r"; break;
case eol_space: strm << " "; break;
default: strm << "\r\n"; break;
}
};
size_t local_indent = indent + 1;
strm << "{";
put_eol();
std::string indent_str = make_indent(local_indent);
if(sec.m_entries.size())
{
auto it_last = --sec.m_entries.end();
for(auto it = sec.m_entries.begin(); it!= sec.m_entries.end();it++)
{
strm << indent_str << "\"" << misc_utils::parse::transform_to_json_escape_sequence(it->first) << "\"" << ": ";
dump_as_json(strm, it->second, local_indent, eol);
if(it_last != it)
strm << ",";
put_eol();
}
}
strm << make_indent(indent) << "}";
}
}
}

1
contrib/jwt-cpp Submodule

@ -0,0 +1 @@
Subproject commit 364a5572f4b46bb9f4304cb1c92acec8ddb2c620

View file

@ -1,4 +1,3 @@
cmake_minimum_required(VERSION 2.4.4)
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
project(zlib C)

View file

@ -196,10 +196,10 @@ if(BUILD_GUI)
ENABLE_SHARED_PCH(Zano QTDAEMON)
ENABLE_SHARED_PCH_EXECUTABLE(Zano)
QT5_USE_MODULES(Zano WebEngineWidgets WebChannel)
#QT5_USE_MODULES(Zano WebEngineWidgets WebChannel)
find_package(Qt5PrintSupport REQUIRED)
target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebChannel Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
if (UNIX AND NOT APPLE)
target_link_libraries(Zano rt)
endif()

View file

@ -25,7 +25,7 @@ namespace command_line
const arg_descriptor<bool> arg_console ( "no-console", "Disable daemon console commands" );
const arg_descriptor<bool> arg_show_details ( "currency-details", "Display currency details" );
const arg_descriptor<bool> arg_show_rpc_autodoc ( "show_rpc_autodoc", "Display rpc auto-generated documentation template" );
const arg_descriptor<std::string> arg_generate_rpc_autodoc ( "generate-rpc-autodoc", "Make auto-generated RPC API documentation documents at the given path" );
const arg_descriptor<bool> arg_disable_upnp ( "disable-upnp", "Disable UPnP (enhances local network privacy)");
const arg_descriptor<bool> arg_disable_ntp ( "disable-ntp", "Disable NTP, could enhance to time synchronization issue but increase network privacy, consider using disable-stop-if-time-out-of-sync with it");

View file

@ -220,7 +220,7 @@ namespace command_line
extern const arg_descriptor<int> arg_log_level;
extern const arg_descriptor<bool> arg_console;
extern const arg_descriptor<bool> arg_show_details;
extern const arg_descriptor<bool> arg_show_rpc_autodoc;
//extern const arg_descriptor<bool> arg_show_rpc_autodoc;
extern const arg_descriptor<bool> arg_disable_upnp;
extern const arg_descriptor<bool> arg_disable_ntp;
extern const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync;
@ -233,4 +233,6 @@ namespace command_line
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;
extern const arg_descriptor<std::string> arg_generate_rpc_autodoc;
}

View file

@ -14,6 +14,7 @@
#define VARIANT_SWITCH_END() } }
#define VARIANT_OBJ_TYPENAME local_reference_eokcmeokmeokcm.type().name()
/*

View file

@ -1043,7 +1043,7 @@ namespace crypto
void zero()
{
PUSH_GCC_WARNINGS
DISABLE_GCC_AND_CLANG_WARNING(class-memaccess)
DISABLE_GCC_WARNING(class-memaccess)
size_t size_bytes = sizeof(scalar_t) * size();
memset(data(), 0, size_bytes);
POP_GCC_WARNINGS
@ -1202,15 +1202,6 @@ namespace crypto
void add_point(const point_t& point)
{
m_elements.emplace_back(point.to_public_key());
// faster?
/* static_assert(sizeof point.m_p3 == 5 * sizeof(item_t), "size missmatch");
const item_t *p = (item_t*)&point.m_p3;
m_elements.emplace_back(p[0]);
m_elements.emplace_back(p[1]);
m_elements.emplace_back(p[2]);
m_elements.emplace_back(p[3]);
m_elements.emplace_back(p[4]); */
}
void add_pub_key(const crypto::public_key& pk)

View file

@ -100,7 +100,6 @@ namespace crypto
}
// TODO: refactor with proper OOB handling
// TODO: @#@# add domain separation
static const point_t& get_generator(bool select_H, size_t index)
{
if (index >= c_bpp_mn_max)

View file

@ -67,6 +67,8 @@ using namespace currency;
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_LAST_WORKED_VERSION 2
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 3 //DON'T CHANGE THIS, if you need to resync db change BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION 4 //mismatch here means some reinitializations
#define BLOCKCHAIN_STORAGE_OPTIONS_ID_MAJOR_FAILURE 5 //if not blocks should ever be added with this condition
#define TARGETDATA_CACHE_SIZE DIFFICULTY_WINDOW + 10
@ -96,6 +98,7 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m
m_db_last_worked_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_LAST_WORKED_VERSION, m_db_solo_options),
m_db_storage_major_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION, m_db_solo_options),
m_db_storage_minor_compatibility_version(BLOCKCHAIN_STORAGE_OPTIONS_ID_STORAGE_MINOR_COMPATIBILITY_VERSION, m_db_solo_options),
m_db_major_failure(BLOCKCHAIN_STORAGE_OPTIONS_ID_MAJOR_FAILURE, m_db_solo_options),
m_db_per_block_gindex_incs(m_db),
m_tx_pool(tx_pool),
m_is_in_checkpoint_zone(false),
@ -297,10 +300,13 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
m_db_addr_to_alias.set_cache_size(cache_size);
}
LOG_PRINT_L0("Opened DB ver " << m_db_storage_major_compatibility_version << "." << m_db_storage_minor_compatibility_version);
bool need_reinit = false;
if (m_db_blocks.size() != 0)
{
#ifndef TESTNET
// MAINNET ONLY
if ((m_db_storage_major_compatibility_version == 93 || m_db_storage_major_compatibility_version == 94) && BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION == 95)
{
// migrate DB to rebuild aliases container
@ -379,14 +385,21 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
// do not reinit db if moving from version 93 to version 94
LOG_PRINT_MAGENTA("DB storage does not need reinit because moving from v93 to v94", LOG_LEVEL_0);
}
#define DB_MAJ_VERSION_FOR_PER_BLOCK_GINDEX_FIX 95
#else
// TESTNET
// TESTNET ONLY
if (m_db_storage_major_compatibility_version == 95 && BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION == 96)
{
// do not reinit TESTNET db if moving from version 95 to version 96
LOG_PRINT_MAGENTA("DB storage does not need reinit because moving from v95 to v96", LOG_LEVEL_0);
}
#define DB_MAJ_VERSION_FOR_PER_BLOCK_GINDEX_FIX 109
#endif
// MAINNET and TESTNET
else if (m_db_storage_major_compatibility_version != BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION)
{
need_reinit = true;
@ -398,6 +411,46 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
need_reinit = true;
LOG_PRINT_MAGENTA("DB storage needs reinit because it has minor compatibility ver " << m_db_storage_minor_compatibility_version << " that is greater than BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION: " << BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION, LOG_LEVEL_0);
}
if (!need_reinit && m_db_storage_major_compatibility_version == DB_MAJ_VERSION_FOR_PER_BLOCK_GINDEX_FIX && m_db_storage_minor_compatibility_version == 1)
{
// such version means that DB has unpopulated container m_db_per_block_gindex_incs, fix it now
LOG_PRINT_MAGENTA("DB version is " << DB_MAJ_VERSION_FOR_PER_BLOCK_GINDEX_FIX << ".1, migrating m_db_per_block_gindex_incs to ver. " << DB_MAJ_VERSION_FOR_PER_BLOCK_GINDEX_FIX << ".2...", LOG_LEVEL_0);
// temporary set db compatibility version to zero during migration in order to trigger db reinit on the next lanunch in case the process stops in the middle
m_db.begin_transaction();
uint64_t tmp_db_maj_version = m_db_storage_major_compatibility_version;
m_db_storage_major_compatibility_version = 0;
m_db.commit_transaction();
m_db.begin_transaction();
std::unordered_map<uint64_t, uint32_t> gindices;
for(size_t height = ZANO_HARDFORK_04_AFTER_HEIGHT + 1, size = m_db_blocks.size(); height < size; ++height)
{
auto block_ptr = m_db_blocks[height];
gindices.clear();
append_per_block_increments_for_tx(block_ptr->bl.miner_tx, gindices);
for(const crypto::hash& tx_id : block_ptr->bl.tx_hashes)
{
auto tx_ptr = m_db_transactions.get(tx_id);
if (!tx_ptr)
{
LOG_ERROR("Internal error: couldn't find a transactions with id " << tx_id << ", migration stops now and full resync is triggered in attempt to fix this.");
need_reinit = true;
break;
}
append_per_block_increments_for_tx(tx_ptr->tx, gindices);
}
push_block_to_per_block_increments(height, gindices);
}
m_db.commit_transaction();
// restore db maj compatibility
m_db.begin_transaction();
m_db_storage_major_compatibility_version = tmp_db_maj_version;
m_db.commit_transaction();
LOG_PRINT_MAGENTA("migration of m_db_per_block_gindex_incs completed successfully", LOG_LEVEL_0);
}
}
if (need_reinit)
@ -452,12 +505,13 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro
set_lost_tx_unmixable();
m_db.commit_transaction();
LOG_PRINT_GREEN("Blockchain initialized. (v:" << m_db_storage_major_compatibility_version << ") last block: " << m_db_blocks.size() - 1 << ENDL
<< "genesis: " << get_block_hash(m_db_blocks[0]->bl) << ENDL
<< "last block: " << m_db_blocks.size() - 1 << ", " << misc_utils::get_time_interval_string(timestamp_diff) << " time ago" << ENDL
<< "current pos difficulty: " << get_next_diff_conditional(true) << ENDL
<< "current pow difficulty: " << get_next_diff_conditional(false) << ENDL
<< "total transactions: " << m_db_transactions.size(),
LOG_PRINT_GREEN("Blockchain initialized, ver: " << m_db_storage_major_compatibility_version << "." << m_db_storage_minor_compatibility_version << ", last block: " << m_db_blocks.size() - 1 << ENDL
<< " genesis: " << get_block_hash(m_db_blocks[0]->bl) << ENDL
<< " last block: " << m_db_blocks.size() - 1 << ", " << misc_utils::get_time_interval_string(timestamp_diff) << " ago" << ENDL
<< " current pos difficulty: " << get_next_diff_conditional(true) << ENDL
<< " current pow difficulty: " << get_next_diff_conditional(false) << ENDL
<< " total transactions: " << m_db_transactions.size() << ENDL
<< " major failure: " << (m_db_major_failure ? "true" : "false"),
LOG_LEVEL_0);
return true;
@ -1131,14 +1185,9 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
return true;
}
//------------------------------------------------------------------
wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) const
void blockchain_storage::collect_timestamps_and_c_difficulties_main(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
std::vector<uint64_t> timestamps;
std::vector<wide_difficulty_type> commulative_difficulties;
if (!m_db_blocks.size())
return DIFFICULTY_POW_STARTER;
//skip genesis timestamp
TIME_MEASURE_START_PD(target_calculating_enum_blocks);
CRITICAL_REGION_BEGIN(m_targetdata_cache_lock);
std::list<std::pair<wide_difficulty_type, uint64_t>>& targetdata_cache = pos ? m_pos_targetdata_cache : m_pow_targetdata_cache;
@ -1153,11 +1202,14 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con
++count;
}
CRITICAL_REGION_END();
wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty;
TIME_MEASURE_FINISH_PD(target_calculating_enum_blocks);
}
//------------------------------------------------------------------
wide_difficulty_type blockchain_storage::calc_diff_at_h_from_timestamps(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, uint64_t h, bool pos) const
{
wide_difficulty_type dif;
TIME_MEASURE_START_PD(target_calculating_calc);
if (m_core_runtime_config.is_hardfork_active_for_height(1, m_db_blocks.size()))
if (m_core_runtime_config.is_hardfork_active_for_height(1, h))
{
dif = next_difficulty_2(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
}
@ -1165,22 +1217,36 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con
{
dif = next_difficulty_1(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
}
TIME_MEASURE_FINISH_PD(target_calculating_calc);
return dif;
}
//------------------------------------------------------------------
wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const
wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
{
//skip genesis timestamp
CRITICAL_REGION_LOCAL(m_read_lock);
if (!m_db_blocks.size())
return DIFFICULTY_POW_STARTER;
}
std::vector<uint64_t> timestamps;
std::vector<wide_difficulty_type> commulative_difficulties;
size_t count = 0;
if (!m_db_blocks.size())
return DIFFICULTY_POW_STARTER;
collect_timestamps_and_c_difficulties_main(timestamps, commulative_difficulties, pos);
auto cb = [&](const block_extended_info& bei, bool is_main){
wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty;
dif = calc_diff_at_h_from_timestamps(timestamps, commulative_difficulties, m_db_blocks.size(), pos);
return dif;
}
//------------------------------------------------------------------
void blockchain_storage::collect_timestamps_and_c_difficulties_alt(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
size_t count = 0;
auto cb = [&](const block_extended_info& bei, bool is_main) {
if (!bei.height)
return false;
bool is_pos_bl = is_pos_block(bei.bl);
@ -1192,15 +1258,22 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, co
if (count >= DIFFICULTY_WINDOW)
return false;
return true;
};
};
enum_blockchain(cb, alt_chain, split_height);
}
//------------------------------------------------------------------
wide_difficulty_type blockchain_storage::get_next_diff_conditional_alt(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const
{
{
CRITICAL_REGION_LOCAL(m_read_lock);
if (!m_db_blocks.size())
return DIFFICULTY_POW_STARTER;
}
std::vector<uint64_t> timestamps;
std::vector<wide_difficulty_type> commulative_difficulties;
collect_timestamps_and_c_difficulties_alt(timestamps, commulative_difficulties, pos, alt_chain, split_height);
wide_difficulty_type diff = 0;
if(m_core_runtime_config.is_hardfork_active_for_height(1, abei.height))
diff = next_difficulty_2(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
else
diff = next_difficulty_1(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter);
return diff;
return calc_diff_at_h_from_timestamps(timestamps, commulative_difficulties, abei.height, pos);
}
//------------------------------------------------------------------
wide_difficulty_type blockchain_storage::get_cached_next_difficulty(bool pos) const
@ -1264,8 +1337,8 @@ wide_difficulty_type blockchain_storage::get_next_difficulty_for_alternative_cha
//------------------------------------------------------------------
bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t height, bool pos) const
{
CHECK_AND_ASSERT_MES((pos ? (b.miner_tx.vin.size() == 2) : (b.miner_tx.vin.size() == 1)), false, "coinbase transaction in the block has no inputs");
CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type");
CHECK_AND_ASSERT_MES((pos ? (b.miner_tx.vin.size() == 2) : (b.miner_tx.vin.size() == 1)), false, "coinbase transaction in the block has incorrect inputs number: " << b.miner_tx.vin.size());
CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "input #0 of the coinbase transaction in the block has the wrong type : " << b.miner_tx.vin[0].type().name());
if(boost::get<txin_gen>(b.miner_tx.vin[0]).height != height)
{
LOG_PRINT_RED_L0("The miner transaction in block has invalid height: " << boost::get<txin_gen>(b.miner_tx.vin[0]).height << ", expected: " << height);
@ -1273,13 +1346,13 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
}
if (pos)
{
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms
if (is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, height)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name());
else
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name());
}
if (m_core_runtime_config.is_hardfork_active_for_height(1, height))
if (is_hardfork_active_for_height(ZANO_HARDFORK_01, height))
{
// new rules that allow different unlock time in coinbase outputs
uint64_t max_unlock_time = 0;
@ -1287,12 +1360,10 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
bool r = get_tx_max_min_unlock_time(b.miner_tx, max_unlock_time, min_unlock_time);
CHECK_AND_ASSERT_MES(r && min_unlock_time >= height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW,
false,
"coinbase transaction has wrong min_unlock_time: " << min_unlock_time << ", expected: " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
"coinbase transaction has wrong min_unlock_time: " << min_unlock_time << ", expected to be greater than or equal to " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
}
else
{
//------------------------------------------------------------------
//bool blockchain_storage::
// pre-hard fork rules that don't allow different unlock time in coinbase outputs
uint64_t max_unlock_time = 0;
uint64_t min_unlock_time = 0;
@ -1304,14 +1375,7 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
}
//check outs overflow
if(!check_outs_overflow(b.miner_tx))
{
LOG_PRINT_RED_L0("miner transaction have money overflow in block " << get_block_hash(b));
return false;
}
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms
if (is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, height)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms
{
CHECK_AND_ASSERT_MES(b.miner_tx.attachment.empty(), false, "coinbase transaction has attachments; attachments are not allowed for coinbase transactions.");
CHECK_AND_ASSERT_MES(b.miner_tx.proofs.size() == 3, false, "coinbase transaction has incorrect number of proofs (" << b.miner_tx.proofs.size() << "), expected 3");
@ -1321,6 +1385,12 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
}
else
{
if(!check_bare_outs_overflow(b.miner_tx))
{
LOG_PRINT_RED_L0("miner transaction have money overflow in block " << get_block_hash(b));
return false;
}
CHECK_AND_ASSERT_MES(b.miner_tx.attachment.empty(), false, "coinbase transaction has attachments; attachments are not allowed for coinbase transactions.");
CHECK_AND_ASSERT_MES(b.miner_tx.proofs.size() == 0, false, "pre-HF4 coinbase shoudn't have non-empty proofs containter");
}
@ -1328,50 +1398,44 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::validate_miner_transaction(const block& b,
size_t cumulative_block_size,
uint64_t fee,
uint64_t& base_reward,
const boost::multiprecision::uint128_t& already_generated_coins) const
bool blockchain_storage::calculate_block_reward_for_next_top_block(size_t next_block_cumulative_size, uint64_t& block_reward_without_fee) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
std::vector<size_t> last_blocks_sizes;
get_last_n_blocks_sizes(last_blocks_sizes, CURRENCY_REWARD_BLOCKS_WINDOW);
size_t blocks_size_median = misc_utils::median(last_blocks_sizes);
if (!get_block_reward(is_pos_block(b), blocks_size_median, cumulative_block_size, already_generated_coins, base_reward, get_block_height(b)))
{
LOG_PRINT_L0("block size " << cumulative_block_size << " is bigger than allowed for this blockchain");
return false;
}
uint64_t block_reward = base_reward;
// before HF4: add tx fee to the block reward; after HF4: burn it
if (b.miner_tx.version < TRANSACTION_VERSION_POST_HF4)
LOG_PRINT_MAGENTA("blocks_size_median = " << blocks_size_median, LOG_LEVEL_2);
block_reward_without_fee = get_block_reward(get_top_block_height() + 1, blocks_size_median, next_block_cumulative_size);
CHECK_AND_ASSERT_MES(block_reward_without_fee != 0, false, "block size " << next_block_cumulative_size << " is bigger than allowed for this blockchain, blocks_size_median: " << blocks_size_median);
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::validate_miner_transaction(const transaction& miner_tx,
uint64_t fee,
uint64_t block_reward_without_fee) const
{
uint64_t block_reward = block_reward_without_fee;
// before HF4: add tx fee to the block reward; after HF4: burn fees, so they don't count in block_reward
if (miner_tx.version < TRANSACTION_VERSION_POST_HF4)
{
block_reward += fee;
}
crypto::hash tx_id_for_post_hf4_era = b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4 ? get_transaction_hash(b.miner_tx) : null_hash;
if (!check_tx_balance(b.miner_tx, tx_id_for_post_hf4_era, block_reward))
crypto::hash tx_id_for_post_hf4_era = miner_tx.version > TRANSACTION_VERSION_PRE_HF4 ? get_transaction_hash(miner_tx) : null_hash; // used in the input context for the proofs for txs ver >= 2
if (!check_tx_balance(miner_tx, tx_id_for_post_hf4_era, block_reward))
{
LOG_ERROR("coinbase transaction balance check failed. Block reward is " << print_money_brief(block_reward) << "(" << print_money(base_reward) << "+" << print_money(fee)
<< ", blocks_size_median = " << blocks_size_median
<< ", cumulative_block_size = " << cumulative_block_size
<< ", fee = " << fee
<< ", already_generated_coins = " << already_generated_coins
<< "), tx:");
LOG_PRINT_L0(currency::obj_to_json_str(b.miner_tx));
LOG_ERROR("coinbase transaction balance check failed. Block reward is " << print_money_brief(block_reward) << " (" << print_money(block_reward_without_fee) << "+" << print_money(fee) << "), tx:");
LOG_PRINT_L0(currency::obj_to_json_str(miner_tx));
return false;
}
if (!verify_asset_surjection_proof(b.miner_tx, tx_id_for_post_hf4_era))
if (!verify_asset_surjection_proof(miner_tx, tx_id_for_post_hf4_era))
{
LOG_ERROR("asset surjection proof verification failed for miner tx");
return false;
}
LOG_PRINT_MAGENTA("Mining tx verification ok, blocks_size_median = " << blocks_size_median, LOG_LEVEL_2);
return true;
}
//------------------------------------------------------------------
@ -1824,7 +1888,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
}
// PoW / PoS validation (heavy checks)
wide_difficulty_type current_diff = get_next_diff_conditional2(pos_block, alt_chain, connection_height, abei);
wide_difficulty_type current_diff = get_next_diff_conditional_alt(pos_block, alt_chain, connection_height, abei);
CHECK_AND_ASSERT_MES_CUSTOM(current_diff, false, bvc.m_verification_failed = true, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
crypto::hash proof_of_work = null_hash;
@ -1910,7 +1974,11 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
std::stringstream ss_pow_pos_info;
if (pos_block)
{
ss_pow_pos_info << "PoS:\t" << abei.stake_hash << ", stake amount: " << print_money(pos_amount) << ", final_difficulty: " << pos_diff_final;
ss_pow_pos_info << "PoS:\t" << abei.stake_hash << ", stake amount: ";
if (abei.bl.miner_tx.version >= TRANSACTION_VERSION_POST_HF4)
ss_pow_pos_info << "hidden";
else
ss_pow_pos_info << print_money_brief(pos_amount) << ", final_difficulty: " << pos_diff_final;
proof = abei.stake_hash;
}
else
@ -3728,7 +3796,6 @@ bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx
CHECK_AND_ASSERT_MES(res, false, "Internal error: multisig out not found, multisig_out_id " << multisig_out_id << "in multisig outs index");
}
VARIANT_CASE_CONST(tx_out_zarcanum, toz)
// TODO: @#@# temporary comment this section and make a test for the corresponding bug
if (!do_pop_output(i, 0))
return false;
VARIANT_CASE_THROW_ON_OTHER();
@ -3806,6 +3873,30 @@ bool blockchain_storage::get_asset_info(const crypto::public_key& asset_id, asse
return false;
}
//------------------------------------------------------------------
uint64_t blockchain_storage::get_assets(uint64_t offset, uint64_t count, std::list<asset_descriptor_with_id>& assets) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
assets.clear();
m_db_assets.enumerate_items([&](uint64_t i, const crypto::public_key& asset_id, const std::list<asset_descriptor_operation>& asset_descriptor_history)
{
if (i < offset)
{
return true;
}
CHECK_AND_ASSERT_THROW_MES(asset_descriptor_history.size(), "asset_descriptor_history unexpectedly have 0 size");
assets.push_back(asset_descriptor_with_id());
static_cast<asset_descriptor_base&>(assets.back()) = asset_descriptor_history.back().descriptor;
assets.back().asset_id = asset_id;
if (i + count > offset)
{
return false;
}
return true;
});
return assets.size();
}
//------------------------------------------------------------------
uint64_t blockchain_storage::get_assets_count() const
{
CRITICAL_REGION_LOCAL(m_read_lock);
@ -4222,16 +4313,17 @@ bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx, cons
bool blockchain_storage::get_outs_index_stat(outs_index_stat& outs_stat) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
outs_stat.amount_0_001 = m_db_outputs.get_item_size(COIN / 1000);
outs_stat.amount_0_01 = m_db_outputs.get_item_size(COIN / 100);
outs_stat.amount_0_1 = m_db_outputs.get_item_size(COIN / 10);
outs_stat.amount_1 = m_db_outputs.get_item_size(COIN);
outs_stat.amount_10 = m_db_outputs.get_item_size(COIN * 10);
outs_stat.amount_100 = m_db_outputs.get_item_size(COIN * 100);
outs_stat.amount_1000 = m_db_outputs.get_item_size(COIN * 1000);
outs_stat.amount_10000 = m_db_outputs.get_item_size(COIN * 10000);
outs_stat.amount_100000 = m_db_outputs.get_item_size(COIN * 100000);
outs_stat.amount_1000000 = m_db_outputs.get_item_size(COIN * 1000000);
outs_stat.amount_0 = m_db_outputs.get_item_size(0);
outs_stat.amount_0_001 = m_db_outputs.get_item_size(COIN / 1000);
outs_stat.amount_0_01 = m_db_outputs.get_item_size(COIN / 100);
outs_stat.amount_0_1 = m_db_outputs.get_item_size(COIN / 10);
outs_stat.amount_1 = m_db_outputs.get_item_size(COIN);
outs_stat.amount_10 = m_db_outputs.get_item_size(COIN * 10);
outs_stat.amount_100 = m_db_outputs.get_item_size(COIN * 100);
outs_stat.amount_1000 = m_db_outputs.get_item_size(COIN * 1000);
outs_stat.amount_10000 = m_db_outputs.get_item_size(COIN * 10000);
outs_stat.amount_100000 = m_db_outputs.get_item_size(COIN * 100000);
outs_stat.amount_1000000 = m_db_outputs.get_item_size(COIN * 1000000);
return true;
}
//------------------------------------------------------------------
@ -4480,7 +4572,6 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const
<< " (fee: " << (is_coinbase(tx) ? "0 [coinbase]" : print_money_brief(get_tx_fee(tx))) << ")");
TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_print_log);
//@#@ del me
// LOG_PRINT_L0("APPEND_TX_TIME_INNER: " << m_performance_data.tx_append_rl_wait.get_last_val()
// << " | " << m_performance_data.tx_append_is_expired.get_last_val()
// << " | " << m_performance_data.tx_process_extra.get_last_val()
@ -4676,7 +4767,8 @@ bool blockchain_storage::print_tx_outputs_lookup(const crypto::hash& tx_id)const
continue;
usage_stat[o.amount][tx_ptr->m_global_output_indexes[i]];
VARIANT_CASE_CONST(tx_out_zarcanum, toz)
//@#@
strm_tx << "[" << i << "]: " << ENDL;
usage_stat[0][tx_ptr->m_global_output_indexes[i]];
VARIANT_SWITCH_END();
}
@ -4839,12 +4931,6 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
}
VARIANT_CASE_CONST(txin_htlc, in_htlc)
{
if (!is_hardfork_active(3)) // @#@ CZ, consider removing this to validate_tx_for_hardfork_specific_terms
{
LOG_ERROR("Error: Transaction with txin_htlc before hardfork 3 (before height " << m_core_runtime_config.hard_forks.get_str_height_the_hardfork_active_after(3) << ")");
return false;
}
CHECK_AND_ASSERT_MES(in_htlc.key_offsets.size(), false, "Empty in_to_key.key_offsets for input #" << sig_index << " tx: " << tx_prefix_hash);
if (!local_check_key_image(in_htlc.k_image))
return false;
@ -4939,7 +5025,7 @@ struct outputs_visitor
//check tx unlock time
uint64_t source_out_unlock_time = get_tx_unlock_time(source_tx, out_i);
//let coinbase sources for PoS block to have locked inputs, the outputs supposed to be locked same way, except the reward
if (is_coinbase(validated_tx) && is_pos_miner_tx(validated_tx)) // @#@ consider changing to one call to is_pos_coinbase()
if (is_pos_miner_tx(validated_tx))
{
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(source_out_unlock_time), false, "source output #" << out_i << " is locked by time, not by height, which is not allowed for PoS coinbase");
if (source_out_unlock_time > m_source_max_unlock_time_for_pos_coinbase)
@ -5126,9 +5212,7 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index,
LOC_CHK(tx.signatures.size() > in_index, "ms input index is out of signatures container bounds, signatures.size() = " << tx.signatures.size());
//@#@
VARIANT_SWITCH_BEGIN(tx.signatures[in_index]);
VARIANT_CASE_CONST(void_sig, v);
VARIANT_CASE_CONST(NLSAG_sig, sig)
{
const std::vector<crypto::signature>& input_signatures = sig.s;
@ -5173,9 +5257,9 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index,
LOC_CHK(r, "failed to check extra signature for last out with TX_FLAG_SIGNATURE_MODE_SEPARATE");
}
}
VARIANT_CASE_CONST(ZC_sig, s);
//@#@
//TODO: don't forget about need_to_check_extra_sign
VARIANT_CASE_OTHER()
LOG_ERROR("Unexpected signature type: " << VARIANT_OBJ_TYPENAME);
return false;
VARIANT_SWITCH_END();
@ -5272,7 +5356,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
CRITICAL_REGION_LOCAL(m_read_lock);
// we need a list<tx_out_zarcanum> this input is referring to
// and make sure that all of them are good (i.e. check 1) source tx unlock time validity; 2) mixin restrictions; 3) general gindex/ref_by_id corectness)
// and make sure that all of them are good (i.e. check: 1) source tx unlock time validity; 2) mixin restrictions; 3) general gindex/ref_by_id corectness)
// get_output_keys_for_input_with_checks is used for that
//
std::vector<crypto::public_key> dummy_output_keys; // won't be used
@ -5448,7 +5532,7 @@ std::shared_ptr<const transaction_chain_entry> blockchain_storage::find_key_imag
{
if (k_image == ki)
{
id_result = get_transaction_hash(tx_chain_entry->tx); // ??? @#@# why not just use tx_id ?
id_result = tx_id;
return tx_chain_entry;
}
}
@ -5690,6 +5774,12 @@ void blockchain_storage::get_pos_mining_estimate(uint64_t amount_coins,
//------------------------------------------------------------------
bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id) const
{
if (m_db_major_failure)
{
LOG_ERROR("MAJOR FAILURE: POS DIFFICULTY IS GOT TO HIGH! Contact the team immediately if you see this error in logs and watch them having panic attack.");
return false;
}
uint64_t block_height = m_db_blocks.size();
return validate_tx_for_hardfork_specific_terms(tx, tx_id, block_height);
}
@ -5847,7 +5937,7 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const
bool blockchain_storage::validate_pre_zarcanum_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const
{
uint64_t major_unlock_time = get_tx_x_detail<etc_tx_details_unlock_time>(miner_tx);
if (major_unlock_time)
@ -5874,7 +5964,7 @@ bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transactio
for (uint64_t i = 0; i != miner_tx.vout.size(); i++)
{
uint64_t unlock_value = ut2.unlock_time_array[i];
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(unlock_value), false, "output #" << i << " is locked by time, not buy height, which is not allowed for PoS coinbase");
CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(unlock_value), false, "output #" << i << " is locked by time, not by height, which is not allowed for PoS coinbase");
if (unlock_value >= source_max_unlock_time)
{
VARIANT_SWITCH_BEGIN(miner_tx.vout[i]);
@ -6051,8 +6141,8 @@ bool blockchain_storage::validate_pos_block(const block& b,
uint64_t last_pow_h = get_last_x_block_height(false);
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to validate coinbase in PoS block, condition failed: max_related_block_height(" << max_related_block_height << ") <= last_pow_h(" << last_pow_h << ")");
//let's check that coinbase amount and unlock time
r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase);
CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b)
r = validate_pre_zarcanum_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase);
CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pre_zarcanum_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b)
<< "source_max_unlock_time_for_pos_coinbase=" << source_max_unlock_time_for_pos_coinbase);
}
else
@ -6504,15 +6594,19 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
return false;
}
boost::multiprecision::uint128_t already_generated_coins = m_db_blocks.size() ? m_db_blocks.back()->already_generated_coins:0;
uint64_t base_reward = get_base_block_reward(is_pos_bl, already_generated_coins, height);
uint64_t block_reward_without_fee = 0;
if (!calculate_block_reward_for_next_top_block(cumulative_block_size, block_reward_without_fee))
{
LOG_ERROR("calculate_block_reward_for_next_top_block filed");
purge_block_data_from_blockchain(bl, tx_processed_count);
bvc.m_verification_failed = true;
return false;
}
if (!m_is_in_checkpoint_zone)
{
// validate_miner_transaction will check balance proof and asset surjection proof
// and, as a side effect, it MAY recalculate base_reward, consider redisign, TODO -- sowle
TIME_MEASURE_START_PD(validate_miner_transaction_time);
if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) // TODO @#@# base_reward will be calculated once again, consider refactoring
if (!validate_miner_transaction(bl.miner_tx, fee_summary, block_reward_without_fee))
{
LOG_PRINT_L0("Block with id: " << id
<< " have wrong miner transaction");
@ -6603,6 +6697,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
//////////////////////////////////////////////////////////////////////////
//etc
boost::multiprecision::uint128_t already_generated_coins = m_db_blocks.size() ? m_db_blocks.back()->already_generated_coins : 0;
if (already_generated_coins < burned_coins)
{
LOG_ERROR("Condition failed: already_generated_coins(" << already_generated_coins << ") >= burned_coins(" << burned_coins << ")");
@ -6610,7 +6705,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
bvc.m_verification_failed = true;
return false;
}
bei.already_generated_coins = already_generated_coins - burned_coins + base_reward;
bei.already_generated_coins = already_generated_coins - burned_coins + block_reward_without_fee;
if (bei.bl.miner_tx.version >= TRANSACTION_VERSION_POST_HF4)
{
bei.already_generated_coins -= fee_summary;
@ -6665,7 +6760,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
TIME_MEASURE_FINISH_PD_MS(block_processing_time_0_ms);
//print result
stringstream powpos_str_entry, timestamp_str_entry, pos_validation_str_entry;
stringstream powpos_str_entry, timestamp_str_entry, pos_validation_str_entry, block_reward_entry;
if (is_pos_bl)
{ // PoS
int64_t actual_ts = get_block_datetime(bei.bl); // signed int is intentionally used here
@ -6687,6 +6782,10 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
powpos_str_entry << "PoW:\t" << proof_hash;
timestamp_str_entry << ", block ts: " << bei.bl.timestamp << " (diff: " << std::showpos << ts_diff << "s)";
}
if(bei.bl.miner_tx.version >= TRANSACTION_VERSION_POST_HF4)
block_reward_entry << "block reward: " << print_money_brief(block_reward_without_fee) << ", fee burnt: " << print_money_brief(fee_summary);
else
block_reward_entry << "block reward: " << print_money_brief(block_reward_without_fee + fee_summary) << " (" << print_money_brief(block_reward_without_fee) << " + " << print_money_brief(fee_summary) << ")";
//explanation of this code will be provided later with public announce
set_lost_tx_unmixable_for_height(bei.height);
@ -6695,8 +6794,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
<< ENDL << "id:\t" << id << timestamp_str_entry.str()
<< ENDL << powpos_str_entry.str()
<< ENDL << "HEIGHT " << bei.height << ", difficulty: " << current_diffic << ", cumul_diff_precise: " << bei.cumulative_diff_precise << ", cumul_diff_precise_adj: " << bei.cumulative_diff_precise_adjusted << " (+" << cumulative_diff_delta << ")"
<< ENDL << "block reward: " << print_money_brief(base_reward + fee_summary) << " (" << print_money_brief(base_reward) << " + " << print_money_brief(fee_summary)
<< ")" << ", coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size << ", tx_count: " << bei.bl.tx_hashes.size()
<< ENDL << block_reward_entry.str() << ", coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size << ", tx_count: " << bei.bl.tx_hashes.size()
<< ", timing: " << block_processing_time_0_ms << "ms"
<< "(micrsec:" << block_processing_time_1
<< "(" << target_calculating_time_2 << "(" << m_performance_data.target_calculating_enum_blocks.get_last_val() << "/" << m_performance_data.target_calculating_calc.get_last_val() << ")"
@ -6711,6 +6809,13 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
<< range_proofs_agregated.size()
<< ")"
<< "))");
if (is_pos_bl && current_diffic > m_core_runtime_config.max_pos_difficulty)
{
m_db_major_failure = true; //burn safety fuse
LOG_ERROR("MAJOR FAILURE: POS DIFFICULTY IS GOT TO HIGH! Contact the team immediately if you see this error in logs and watch them having panic attack."
<< ENDL << "Block id:" << id);
}
{
static epee::math_helper::average<uint64_t, 30> blocks_processing_time_avg_pos, blocks_processing_time_avg_pow;
@ -6823,6 +6928,11 @@ bool blockchain_storage::is_hardfork_active(size_t hardfork_id) const
return m_core_runtime_config.is_hardfork_active_for_height(hardfork_id, m_db_blocks.size()); // note using m_db_blocks.size() ( == top_block_height + 1 )
}
//------------------------------------------------------------------
bool blockchain_storage::is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const
{
return m_core_runtime_config.is_hardfork_active_for_height(hardfork_id, height);
}
//------------------------------------------------------------------
bool blockchain_storage::prevalidate_block(const block& bl)
{
@ -6882,6 +6992,15 @@ bool blockchain_storage::add_new_block(const block& bl, block_verification_conte
{
try
{
if (m_db_major_failure)
{
LOG_PRINT_RED_L0("Block processing is stoped due to MAJOR FAILURE fuse burned");
bvc.m_added_to_main_chain = false;
bvc.m_verification_failed = true;
return false;
}
m_db.begin_transaction();
//block bl = bl_;
@ -6905,10 +7024,6 @@ bool blockchain_storage::add_new_block(const block& bl, block_verification_conte
m_db.commit_transaction();
return false;
}
//check that block refers to chain tail
if (!(bl.prev_id == get_top_block_id()))
{
@ -7358,7 +7473,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
if (!alt_chain.empty())
{
auto abg_it = alt_chain.back()->second.gindex_lookup_table.find(input_amount);
if (abg_it != alt_chain.back()->second.gindex_lookup_table.end())
if (input_amount != 0 /* <-- TODO @#@# remove this condition after ZC outs support is implemented*/ && abg_it != alt_chain.back()->second.gindex_lookup_table.end())
{
amount_touched_altchain = true;
// local gindex lookup table contains last used gindex, so we can't get total number of outs

View file

@ -266,8 +266,12 @@ namespace currency
crypto::hash get_top_block_id(uint64_t& height) const;
bool get_top_block(block& b) const;
wide_difficulty_type get_next_diff_conditional(bool pos) const;
wide_difficulty_type get_next_diff_conditional2(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const;
wide_difficulty_type get_next_diff_conditional_alt(bool pos, const alt_chain_type& alt_chain, uint64_t split_height, const alt_block_extended_info& abei) const;
wide_difficulty_type get_cached_next_difficulty(bool pos) const;
wide_difficulty_type calc_diff_at_h_from_timestamps(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, uint64_t h, bool pos) const;
void collect_timestamps_and_c_difficulties_main(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos) const;
void collect_timestamps_and_c_difficulties_alt(std::vector<uint64_t>& timestamps, std::vector<wide_difficulty_type>& commulative_difficulties, bool pos, const alt_chain_type& alt_chain, uint64_t split_height) const;
bool create_block_template(const account_public_address& miner_address, const blobdata& ex_nonce, block& b, wide_difficulty_type& di, uint64_t& height) const;
@ -302,6 +306,7 @@ namespace currency
bool get_asset_history(const crypto::public_key& asset_id, std::list<asset_descriptor_operation>& result) const;
bool get_asset_info(const crypto::public_key& asset_id, asset_descriptor_base& info)const;
uint64_t get_assets_count() const;
uint64_t get_assets(uint64_t offset, uint64_t count, std::list<asset_descriptor_with_id>& assets) const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
@ -339,7 +344,8 @@ namespace currency
uint64_t get_last_timestamps_check_window_median() const;
uint64_t get_last_n_blocks_timestamps_median(size_t n) const;
bool prevalidate_alias_info(const transaction& tx, const extra_alias_entry& eae);
bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, const boost::multiprecision::uint128_t& already_generated_coins) const;
bool calculate_block_reward_for_next_top_block(size_t next_block_cumulative_size, uint64_t& block_reward_without_fee) const;
bool validate_miner_transaction(const transaction& miner_tx, uint64_t fee, uint64_t block_reward_without_fee) const;
performnce_data& get_performnce_data()const;
bool validate_instance(const std::string& path);
bool is_tx_expired(const transaction& tx) const;
@ -347,6 +353,7 @@ namespace currency
// returns true as soon as the hardfork is active for the NEXT upcoming block (not for the top block in the blockchain storage)
bool is_hardfork_active(size_t hardfork_id) const;
bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const;
bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx) const;
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false) const;
@ -363,7 +370,7 @@ namespace currency
uint64_t timestamp) const;
bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash* p_last_block_hash = nullptr, uint64_t* p_last_pow_block_height = nullptr) const;
bool validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const;
bool validate_pre_zarcanum_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const;
bool validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain)const;
bool validate_pos_block(const block& b, wide_difficulty_type basic_diff, const crypto::hash& id, bool for_altchain)const;
bool validate_pos_block(const block& b,
@ -548,6 +555,8 @@ namespace currency
tools::db::solo_db_value<uint64_t, std::string, solo_options_container, true> m_db_last_worked_version;
tools::db::solo_db_value<uint64_t, uint64_t, solo_options_container> m_db_storage_major_compatibility_version;
tools::db::solo_db_value<uint64_t, uint64_t, solo_options_container> m_db_storage_minor_compatibility_version;
tools::db::solo_db_value<uint64_t, bool, solo_options_container> m_db_major_failure; //safety fuse
outputs_container m_db_outputs;
multisig_outs_container m_db_multisig_outs;
aliases_container m_db_aliases;

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2023 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2012-2013 The Boolberry developers
@ -167,9 +167,9 @@ namespace currency
uint64_t no;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(proposal_id)
KV_SERIALIZE(yes)
KV_SERIALIZE(no)
KV_SERIALIZE(proposal_id) DOC_DSCR("ID of the proposal.") DOC_EXMP("ZAP999") DOC_END
KV_SERIALIZE(yes) DOC_DSCR("Nubmer of positve votes.") DOC_EXMP(42) DOC_END
KV_SERIALIZE(no) DOC_DSCR("Number of negative votes.") DOC_EXMP(37) DOC_END
END_KV_SERIALIZE_MAP()
};
@ -179,8 +179,8 @@ namespace currency
std::list<vote_on_proposal> votes;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total_pos_blocks)
KV_SERIALIZE(votes)
KV_SERIALIZE(total_pos_blocks) DOC_DSCR("Number of blocks in a given range.") DOC_EXMP(87482) DOC_END
KV_SERIALIZE(votes) DOC_DSCR("Result of votes in a given range.") DOC_END
END_KV_SERIALIZE_MAP()
};

View file

@ -106,6 +106,7 @@ namespace currency
crypto::public_key alias_validation_pubkey;
core_time_func_t get_core_time;
uint64_t hf4_minimum_mixins;
wide_difficulty_type max_pos_difficulty;
hard_forks_descriptor hard_forks;
@ -129,6 +130,7 @@ namespace currency
pc.tx_default_fee = TX_DEFAULT_FEE;
pc.max_alt_blocks = CURRENCY_ALT_BLOCK_MAX_COUNT;
pc.hf4_minimum_mixins = CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE;
pc.max_pos_difficulty = wide_difficulty_type(POS_MAX_DIFFICULTY_ALLOWED);
// TODO: refactor the following
pc.hard_forks.set_hardfork_height(1, ZANO_HARDFORK_01_AFTER_HEIGHT);

View file

@ -589,11 +589,11 @@ namespace currency
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)
KV_SERIALIZE(service_id) DOC_DSCR("Service ID, identificator that diferent one service from another") DOC_EXMP("C") DOC_END
KV_SERIALIZE(instruction) DOC_DSCR("Instruction that make sence for this particular service") DOC_EXMP("K") DOC_END
KV_SERIALIZE_BLOB_AS_HEX_STRING(body) DOC_DSCR("Hex-encoded body of the attachment") DOC_EXMP("dcfd7e055a6a3043ea3541a571a57a63e25dcc64e4a270f14fa9a58ac5dbec85dcfd7e055a6a3043ea3541a571a57a63e25dcc64e4a270f14fa9a58ac5dbec85") DOC_END
KV_SERIALIZE_CONTAINER_POD_AS_HEX(security) DOC_DSCR("Hex-encoded public key of the owner, optional") DOC_EXMP("d8f6e37f28a632c06b0b3466db1b9d2d1b36a580ee35edfd971dc1423bc412a5") DOC_END
KV_SERIALIZE(flags) DOC_DSCR("Flags that help wallet to automatically process some properties of the attachment(combination of TX_SERVICE_ATTACHMENT_ENCRYPT_BODY=1, TX_SERVICE_ATTACHMENT_DEFLATE_BODY=2, TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE=4,TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF=8 )") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -732,14 +732,14 @@ namespace currency
END_BOOST_SERIALIZATION()
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total_max_supply)
KV_SERIALIZE(current_supply)
KV_SERIALIZE(decimal_point)
KV_SERIALIZE(ticker)
KV_SERIALIZE(full_name)
KV_SERIALIZE(meta_info)
KV_SERIALIZE_POD_AS_HEX_STRING(owner)
KV_SERIALIZE(hidden_supply)
KV_SERIALIZE(total_max_supply) DOC_DSCR("Maximum possible supply for given asset, can't be changed after deployment") DOC_EXMP(1000000000000000000) DOC_END
KV_SERIALIZE(current_supply) DOC_DSCR("Currently emitted supply for given asset") DOC_EXMP(500000000000000000) DOC_END
KV_SERIALIZE(decimal_point) DOC_DSCR("Decimal point") DOC_EXMP(12) DOC_END
KV_SERIALIZE(ticker) DOC_DSCR("Ticker associated with asset") DOC_EXMP("ZUSD") DOC_END
KV_SERIALIZE(full_name) DOC_DSCR("Full name of the asset") DOC_EXMP("Zano wrapped USD") DOC_END
KV_SERIALIZE(meta_info) DOC_DSCR("Any other information assetiaded with asset in a free form") DOC_EXMP("Stable and private") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(owner) DOC_DSCR("Owner's key, used to validate any operations on the asset altering, could be changed in case of transfer ownership") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
KV_SERIALIZE(hidden_supply) DOC_DSCR("This one reserved for future use, will be documented later") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -757,7 +757,7 @@ namespace currency
BEGIN_KV_SERIALIZE_MAP()
KV_CHAIN_BASE(asset_descriptor_base)
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id)
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) DOC_DSCR("Asset ID") DOC_EXMP("f74bb56a5b4fa562e679ccaadd697463498a66de4f1760b2cd40f11c3a00a7a8") DOC_END
END_KV_SERIALIZE_MAP()
};

View file

@ -157,6 +157,8 @@
#define POS_MODFIFIER_INTERVAL 10
#define POS_WALLET_MINING_SCAN_INTERVAL POS_SCAN_STEP //seconds
#define POS_MINIMUM_COINSTAKE_AGE 10 // blocks count
#define POS_MAX_DIFFICULTY_ALLOWED "25000000000000000000000" // maximum expected PoS difficuty (need to change it probaly in 20 years)
#ifndef TESTNET
# define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 57000
@ -243,14 +245,14 @@
#define CURRENT_BLOCK_EXTENDED_INFO_ARCHIVE_VER 1
#define BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION CURRENCY_FORMATION_VERSION + 11
#define BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION 1
#define BLOCKCHAIN_STORAGE_MINOR_COMPATIBILITY_VERSION 2
#define BC_OFFERS_CURRENT_OFFERS_SERVICE_ARCHIVE_VER CURRENCY_FORMATION_VERSION + BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 9
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
#define WALLET_FILE_SERIALIZATION_VERSION 165
#define WALLET_FILE_SERIALIZATION_VERSION 167
#define WALLET_FILE_LAST_SUPPORTED_VERSION 165
#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31)
@ -265,6 +267,7 @@
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 // 2021-06-01 23:28:10
#define ZANO_HARDFORK_04_AFTER_HEIGHT 2555000 // 2024-03-21 11:49:55
#define ZANO_HARDFORK_05_AFTER_HEIGHT 999999999999999999
#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1711021795ull // block 2555000, 2024-03-21 11:49:55 UTC
#else
/////// Zarcanum Testnet //////////////////////////////
#define ZANO_HARDFORK_01_AFTER_HEIGHT 0
@ -272,6 +275,7 @@
#define ZANO_HARDFORK_03_AFTER_HEIGHT 0
#define ZANO_HARDFORK_04_AFTER_HEIGHT 200
#define ZANO_HARDFORK_05_AFTER_HEIGHT 200
#define ZANO_HARDFORK_04_TIMESTAMP_ACTUAL 1712785801ull // block 200, 2024-04-10 21:50:01 UTC
#endif

View file

@ -261,6 +261,34 @@ namespace currency
return diff;
}
//------------------------------------------------------------------
bool add_random_derivation_hints_and_put_them_to_tx(uint8_t tx_flags, const std::set<uint16_t>& existing_derivation_hints, std::set<uint16_t>& new_derivation_hints, transaction& tx)
{
if (existing_derivation_hints.size() > tx.vout.size())
{
if (tx.version < TRANSACTION_VERSION_POST_HF4 && (tx_flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)) // for pre-HF4 consolidated txs just skip if all hints are already added
return true;
return false;
}
size_t hints_to_be_added = tx.vout.size() - existing_derivation_hints.size();
size_t attempts_cnt = 0, attempts_max = 4096;
while(new_derivation_hints.size() < hints_to_be_added && ++attempts_cnt < attempts_max)
{
uint16_t hint = crypto::rand<uint16_t>();
if (existing_derivation_hints.count(hint) == 0)
new_derivation_hints.insert(hint);
}
if (attempts_cnt == attempts_max)
return false;
for(auto& el : new_derivation_hints) // iterating in sorted sequence
tx.extra.push_back(make_tx_derivation_hint_from_uint16(el));
return true;
}
//---------------------------------------------------------------
bool generate_tx_balance_proof(const transaction &tx, const crypto::hash& tx_id, const tx_generation_context& ogc, uint64_t block_reward_for_miner_tx, currency::zc_balance_proof& proof)
{
CHECK_AND_ASSERT_MES(tx.version > TRANSACTION_VERSION_PRE_HF4, false, "unsupported tx.version: " << tx.version);
@ -488,12 +516,12 @@ namespace currency
// fill outputs
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;
std::set<uint16_t> derivation_hints;
for (auto& d : destinations)
{
finalized_tx result = AUTO_VAL_INIT(result);
uint8_t tx_outs_attr = 0;
r = construct_tx_out(d, tx_gen_context.tx_key.sec, output_index, tx, deriv_cache, account_keys(),
r = construct_tx_out(d, tx_gen_context.tx_key.sec, output_index, tx, derivation_hints, 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));
@ -504,6 +532,7 @@ namespace currency
tx_gen_context.amount_commitments_sum += tx_gen_context.amount_commitments[output_index];
++output_index;
}
CHECK_AND_ASSERT_MES(add_random_derivation_hints_and_put_them_to_tx(0, std::set<uint16_t>(), derivation_hints, tx), false, "add_random_derivation_hints_and_put_them_to_tx failed");
if (tx.attachment.size())
add_attachments_info_to_extra(tx.extra, tx.attachment);
@ -1117,14 +1146,13 @@ namespace currency
return dh;
}
//---------------------------------------------------------------
// bool get_uint16_from_tx_derivation_hint(const tx_derivation_hint& dh, uint16_t& hint)
// {
// tx_derivation_hint dh;
// if (dh.msg.size() != sizeof(hint))
// return false;
// hint = *((uint16_t*)dh.msg.data());
// return true;
// }
bool get_uint16_from_tx_derivation_hint(const tx_derivation_hint& dh, uint16_t& hint)
{
if (dh.msg.size() != sizeof(hint))
return false;
hint = *((uint16_t*)dh.msg.data());
return true;
}
//---------------------------------------------------------------
std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys)
{
@ -1257,11 +1285,7 @@ namespace currency
out.mix_attr = tx_outs_attr;
uint16_t hint = get_derivation_hint(reinterpret_cast<crypto::key_derivation&>(derivation));
if (deriv_cache.count(hint) == 0)
{
tx.extra.push_back(make_tx_derivation_hint_from_uint16(hint));
deriv_cache.insert(hint);
}
deriv_cache.insert(hint); // won't be inserted if such hint already exists
}
tx.vout.push_back(out);
@ -1289,11 +1313,7 @@ namespace currency
CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address");
uint16_t hint = get_derivation_hint(derivation);
if (deriv_cache.count(hint) == 0)
{
tx.extra.push_back(make_tx_derivation_hint_from_uint16(hint));
deriv_cache.insert(hint);
}
deriv_cache.insert(hint); // won't be inserted if such hint already exists
}
target_keys.push_back(out_eph_public_key);
}
@ -1318,11 +1338,7 @@ namespace currency
htlc.pkey_refund = out_eph_public_key;
//add derivation hint for refund address
uint16_t hint = get_derivation_hint(derivation);
if (deriv_cache.count(hint) == 0)
{
tx.extra.push_back(make_tx_derivation_hint_from_uint16(hint));
deriv_cache.insert(hint);
}
deriv_cache.insert(hint); // won't be inserted if such hint already exists
if (htlc_dest.htlc_hash == null_hash)
@ -1912,7 +1928,22 @@ namespace currency
}
return n;
}
//---------------------------------------------------------------
bool copy_all_derivation_hints_from_tx_to_container(transaction& tx, std::set<uint16_t>& derivation_hints)
{
for(auto it = tx.extra.begin(); it != tx.extra.end(); ++it)
{
if (it->type() == typeid(tx_derivation_hint))
{
uint16_t hint = 0;
if (!get_uint16_from_tx_derivation_hint(boost::get<tx_derivation_hint>(*it), hint))
return false;
if (!derivation_hints.insert(hint).second)
return false; // maybe we need to skip this?
}
}
return true;
}
//---------------------------------------------------------------
bool construct_tx(const account_keys& sender_account_keys,
const std::vector<tx_source_entry>& sources,
@ -2582,14 +2613,15 @@ namespace currency
uint64_t native_coins_output_sum = 0;
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1
uint64_t range_proof_start_index = 0;
std::set<uint16_t> deriv_cache;
std::set<uint16_t> existing_derivation_hints, new_derivation_hints;
CHECK_AND_ASSERT_MES(copy_all_derivation_hints_from_tx_to_container(tx, existing_derivation_hints), false, "move_all_derivation_hints_from_tx_to_container failed");
for(size_t destination_index = 0; destination_index < shuffled_dsts.size(); ++destination_index, ++output_index)
{
tx_destination_entry& dst_entr = shuffled_dsts[destination_index];
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, gen_context.tx_key.sec, output_index, tx, deriv_cache, sender_account_keys,
r = construct_tx_out(dst_entr, gen_context.tx_key.sec, output_index, tx, new_derivation_hints, 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");
@ -2602,6 +2634,8 @@ namespace currency
native_coins_output_sum += dst_entr.amount;
}
CHECK_AND_ASSERT_MES(add_random_derivation_hints_and_put_them_to_tx(flags, existing_derivation_hints, new_derivation_hints, tx), false, "add_random_derivation_hints_and_put_them_to_tx failed");
//process offers and put there offers derived keys
uint64_t att_count = 0;
for (auto& o : tx.attachment)
@ -2780,6 +2814,7 @@ namespace currency
return CURRENT_TRANSACTION_VERSION;
}
//---------------------------------------------------------------
// TODO @#@# this function is obsolete and needs to be re-written
uint64_t get_reward_from_miner_tx(const transaction& tx)
{
uint64_t income = 0;
@ -3083,12 +3118,12 @@ namespace currency
return true;
}
//-----------------------------------------------------------------------------------------------
bool check_money_overflow(const transaction& tx)
bool check_bare_money_overflow(const transaction& tx)
{
return check_inputs_overflow(tx) && check_outs_overflow(tx);
return check_bare_inputs_overflow(tx) && check_bare_outs_overflow(tx);
}
//---------------------------------------------------------------
bool check_inputs_overflow(const transaction& tx)
bool check_bare_inputs_overflow(const transaction& tx)
{
uint64_t money = 0;
for(const auto& in : tx.vin)
@ -3125,7 +3160,7 @@ namespace currency
return true;
}
//---------------------------------------------------------------
bool check_outs_overflow(const transaction& tx)
bool check_bare_outs_overflow(const transaction& tx)
{
uint64_t money = 0;
for(const auto& o : tx.vout)
@ -4022,7 +4057,7 @@ namespace currency
pei_rpc.miner_text_info = eud.buff;
}
pei_rpc.base_reward = get_base_block_reward(is_pos_block(bei_chain.bl), bei_chain.already_generated_coins, bei_chain.height);
pei_rpc.base_reward = get_base_block_reward(bei_chain.height);
pei_rpc.summary_reward = get_reward_from_miner_tx(bei_chain.bl.miner_tx);
pei_rpc.penalty = (pei_rpc.base_reward + pei_rpc.total_fee) - pei_rpc.summary_reward;
return true;
@ -4041,7 +4076,7 @@ namespace currency
gindices[amount] += 1;
}
VARIANT_CASE_CONST(tx_out_zarcanum, o)
//@#@
gindices[0] += 1;
VARIANT_SWITCH_END();
}
}
@ -4075,7 +4110,7 @@ namespace currency
return CURRENCY_MAX_BLOCK_SIZE;
}
//-----------------------------------------------------------------------------------------------
uint64_t get_base_block_reward(bool is_pos, const boost::multiprecision::uint128_t& already_generated_coins, uint64_t height)
uint64_t get_base_block_reward(uint64_t height)
{
if (!height)
return PREMINE_AMOUNT;
@ -4083,9 +4118,18 @@ namespace currency
return CURRENCY_BLOCK_REWARD;
}
//-----------------------------------------------------------------------------------------------
// Modern version, requires only necessary arguments. Returns 0 if block is too big (current_block_size > 2 * median_block_size)
uint64_t get_block_reward(uint64_t height, size_t median_block_size, size_t current_block_size)
{
uint64_t reward = 0;
get_block_reward(/* is_pos - doesn't matter */ false, median_block_size, current_block_size, /* boost::multiprecision::uint128_t -- doesn't matter*/ boost::multiprecision::uint128_t(0), reward, height);
return reward;
}
//-----------------------------------------------------------------------------------------------
// legacy version, some arguments are unnecessary now
bool get_block_reward(bool is_pos, size_t median_size, size_t current_block_size, const boost::multiprecision::uint128_t& already_generated_coins, uint64_t &reward, uint64_t height)
{
uint64_t base_reward = get_base_block_reward(is_pos, already_generated_coins, height);
uint64_t base_reward = get_base_block_reward(height);
//make it soft
if (median_size < CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE)

View file

@ -414,9 +414,9 @@ namespace currency
uint64_t get_alias_coast_from_fee(const std::string& alias, uint64_t fee_median);
//const crypto::public_key get_offer_secure_key_by_index_from_tx(const transaction& tx, size_t index);
bool check_money_overflow(const transaction& tx);
bool check_outs_overflow(const transaction& tx);
bool check_inputs_overflow(const transaction& tx);
bool check_bare_money_overflow(const transaction& tx);
bool check_bare_outs_overflow(const transaction& tx);
bool check_bare_inputs_overflow(const transaction& tx);
uint64_t get_block_height(const transaction& coinbase);
uint64_t get_block_height(const block& b);
std::vector<txout_ref_v> relative_output_offsets_to_absolute(const std::vector<txout_ref_v>& off);
@ -522,8 +522,9 @@ namespace currency
/************************************************************************/
size_t get_max_block_size();
size_t get_max_tx_size();
uint64_t get_block_reward(uint64_t height, size_t median_block_size, size_t current_block_size);
bool get_block_reward(bool is_pos, size_t median_size, size_t current_block_size, const boost::multiprecision::uint128_t& already_generated_coins, uint64_t &reward, uint64_t height);
uint64_t get_base_block_reward(bool is_pos, const boost::multiprecision::uint128_t& already_generated_coins, uint64_t height);
uint64_t get_base_block_reward(uint64_t height);
bool is_payment_id_size_ok(const payment_id_t& payment_id);
std::string get_account_address_as_str(const account_public_address& addr);
std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const payment_id_t& payment_id);
@ -535,6 +536,20 @@ namespace currency
bool is_pos_coinbase(const transaction& tx);
bool have_attachment_service_in_container(const std::vector<attachment_v>& av, const std::string& service_id, const std::string& instruction);
crypto::hash prepare_prefix_hash_for_sign(const transaction& tx, uint64_t in_index, const crypto::hash& tx_id);
//---------------------------------------------------------------
template<typename t_assets_map>
void assets_map_to_assets_list(std::list<currency::asset_descriptor_with_id>& assets_list, const t_assets_map& assets_map)
{
for (const auto& pr : assets_map)
{
assets_list.push_back(currency::asset_descriptor_with_id());
assets_list.back().asset_id = pr.first;
epee::misc_utils::cast_assign_a_to_b(assets_list.back(), static_cast<currency::asset_descriptor_base>(pr.second));
//*static_cast<currency::asset_descriptor_base*>(&assets_list.back()) = pr.second;
}
}
//---------------------------------------------------------------
template<class tx_out_t>

View file

@ -37,21 +37,21 @@ namespace bc_services
//-----------------
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_N(offer_type, "ot")
KV_SERIALIZE_CUSTOM_N(amount_primary, std::string, bc_services::transform_amount_to_string, bc_services::transform_string_to_amount, "ap")
KV_SERIALIZE_CUSTOM_N(amount_target, std::string, bc_services::transform_amount_to_string, bc_services::transform_string_to_amount, "at")
KV_SERIALIZE_N(bonus, "b")
KV_SERIALIZE_N(target, "t")
KV_SERIALIZE_N(primary, "p")
KV_SERIALIZE_N(location_country, "lco")
KV_SERIALIZE_N(location_city, "lci")
KV_SERIALIZE_N(contacts, "cnt")
KV_SERIALIZE_N(comment, "com")
KV_SERIALIZE_N(payment_types, "pt")
KV_SERIALIZE_N(deal_option, "do")
KV_SERIALIZE_N(category, "cat")
KV_SERIALIZE_N(expiration_time, "et")
KV_SERIALIZE_N(preview_url, "url")
KV_SERIALIZE_N(offer_type, "ot") DOC_DSCR("Type of the offer: OFFER_TYPE_PRIMARY_TO_TARGET(SELL ORDER) - 0, OFFER_TYPE_TARGET_TO_PRIMARY(BUY ORDER) - 1 etc.") DOC_EXMP(0) DOC_END
KV_SERIALIZE_CUSTOM_N(amount_primary, std::string, bc_services::transform_amount_to_string, bc_services::transform_string_to_amount, "ap") DOC_DSCR("Amount of the currency") DOC_EXMP("100000") DOC_END
KV_SERIALIZE_CUSTOM_N(amount_target, std::string, bc_services::transform_amount_to_string, bc_services::transform_string_to_amount, "at") DOC_DSCR("Smount of other currency or goods") DOC_EXMP("10000000") DOC_END
KV_SERIALIZE_N(bonus, "b") DOC_DSCR("Bonus associated with the offer") DOC_EXMP("") DOC_END
KV_SERIALIZE_N(target, "t") DOC_DSCR("Target: currency / goods") DOC_EXMP("USDT") DOC_END
KV_SERIALIZE_N(primary, "p") DOC_DSCR("Currency for goods") DOC_EXMP("ZANO") DOC_END
KV_SERIALIZE_N(location_country, "lco") DOC_DSCR("Country of the offer location") DOC_EXMP("Montenegro") DOC_END
KV_SERIALIZE_N(location_city, "lci") DOC_DSCR("City of the offer location") DOC_EXMP("Kolasin") DOC_END
KV_SERIALIZE_N(contacts, "cnt") DOC_DSCR("Contacts related to the offer") DOC_EXMP("Ranko +38211111111") DOC_END
KV_SERIALIZE_N(comment, "com") DOC_DSCR("Comment associated with the offer") DOC_EXMP("Dobr dan") DOC_END
KV_SERIALIZE_N(payment_types, "pt") DOC_DSCR("Types of payment accepted for the offer") DOC_EXMP("zano") DOC_END
KV_SERIALIZE_N(deal_option, "do") DOC_DSCR("Deal option for the offer") DOC_EXMP("full amount, by parts") DOC_END
KV_SERIALIZE_N(category, "cat") DOC_DSCR("Category of the offer") DOC_EXMP("") DOC_END
KV_SERIALIZE_N(expiration_time, "et") DOC_DSCR("Expiration time of the offer") DOC_EXMP(0) DOC_END
KV_SERIALIZE_N(preview_url, "url") DOC_DSCR("URL for previewing the offer") DOC_EXMP("") DOC_END
END_KV_SERIALIZE_MAP()
};
@ -69,12 +69,12 @@ namespace bc_services
mutable bool stopped;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_POD_AS_HEX_STRING(tx_hash)
KV_SERIALIZE_POD_AS_HEX_STRING(tx_original_hash)
KV_SERIALIZE(index_in_tx)
KV_SERIALIZE(timestamp)
KV_SERIALIZE(fee)
KV_SERIALIZE_POD_AS_HEX_STRING(security)
KV_SERIALIZE_POD_AS_HEX_STRING(tx_hash) DOC_DSCR("Transaction hash represented as a hexadecimal string") DOC_EXMP("cc608f59f8080e2fbfe3c8c80eb6e6a953d47cf2d6aebd345bada3a1cab99852") DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(tx_original_hash) DOC_DSCR("Origin transaction hash represented as a hexadecimal string(if offer updated)") DOC_EXMP("cc608f59f8080e2fbfe3c8c80eb6e6a953d47cf2d6aebd345bada3a1cab99852") DOC_END
KV_SERIALIZE(index_in_tx) DOC_DSCR("Index of the tx_service_attachment entrie in transaction") DOC_EXMP(0) DOC_END
KV_SERIALIZE(timestamp) DOC_DSCR("Timestamp of the transaction") DOC_EXMP(1712683857) DOC_END
KV_SERIALIZE(fee) DOC_DSCR("Fee associated with the transaction") DOC_EXMP(10000000000) DOC_END
KV_SERIALIZE_POD_AS_HEX_STRING(security) DOC_DSCR("Onwer's public key for access control") DOC_EXMP("40fa6db923728b38962718c61b4dc3af1acaa1967479c73703e260dc3609c58d") DOC_END
KV_CHAIN_BASE(offer_details)
END_KV_SERIALIZE_MAP()
};
@ -163,32 +163,33 @@ namespace bc_services
bool bonus;
std::string category;
std::string keyword;
bool fake;
//bool fake;
uint64_t current_time;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(order_by)
KV_SERIALIZE(reverse)
KV_SERIALIZE(offset)
KV_SERIALIZE(limit)
KV_SERIALIZE(timestamp_start)
KV_SERIALIZE(timestamp_stop)
KV_SERIALIZE(offer_type_mask)
KV_SERIALIZE(amount_low_limit)
KV_SERIALIZE(amount_up_limit)
KV_SERIALIZE_CUSTOM(rate_low_limit, std::string, bc_services::transform_double_to_string, bc_services::transform_string_to_double)
KV_SERIALIZE_CUSTOM(rate_up_limit, std::string, bc_services::transform_double_to_string, bc_services::transform_string_to_double)
KV_SERIALIZE(payment_types)
KV_SERIALIZE(location_country)
KV_SERIALIZE(location_city)
KV_SERIALIZE(target)
KV_SERIALIZE(primary)
KV_SERIALIZE(bonus)
KV_SERIALIZE(category)
KV_SERIALIZE(keyword)
KV_SERIALIZE(fake)
KV_SERIALIZE(order_by) DOC_DSCR("Field to order the results by one on this: ORDER_BY_TIMESTAMP=0,ORDER_BY_AMOUNT_PRIMARY=1,ORDER_BY_AMOUNT_TARGET=2,ORDER_BY_AMOUNT_RATE=3,ORDER_BY_PAYMENT_TYPES=4,ORDER_BY_CONTACTS=5,ORDER_BY_LOCATION=6,ORDER_BY_NAME=7") DOC_EXMP(0) DOC_END
KV_SERIALIZE(reverse) DOC_DSCR("Flag to indicate whether the results should be sorted in reverse order") DOC_EXMP(false) DOC_END
KV_SERIALIZE(offset) DOC_DSCR("Offset for pagination") DOC_EXMP(0) DOC_END
KV_SERIALIZE(limit) DOC_DSCR("Maximum number of results to return") DOC_EXMP(100) DOC_END
KV_SERIALIZE(timestamp_start) DOC_DSCR("Start timestamp for filtering results") DOC_EXMP(0) DOC_END
KV_SERIALIZE(timestamp_stop) DOC_DSCR("Stop timestamp for filtering results") DOC_EXMP(0) DOC_END
KV_SERIALIZE(offer_type_mask) DOC_DSCR("Mask representing the types of offers to include in the results, conbination of this: OFFER_TYPE_MASK_PRIMARY_TO_TARGET 0x00000001, OFFER_TYPE_MASK_TARGET_TO_PRIMARY 0x00000002, OFFER_TYPE_MASK_GOODS_TO_PRIMARY 0x00000004, OFFER_TYPE_MASK_PRIMARY_TO_GOODS 0x00000008") DOC_EXMP(0) DOC_END
KV_SERIALIZE(amount_low_limit) DOC_DSCR("Lower limit for the amount of offers") DOC_EXMP(0) DOC_END
KV_SERIALIZE(amount_up_limit) DOC_DSCR("Upper limit for the amount of offers") DOC_EXMP(0) DOC_END
KV_SERIALIZE_CUSTOM(rate_low_limit, std::string, bc_services::transform_double_to_string, bc_services::transform_string_to_double) DOC_DSCR("Lower limit for the rate") DOC_EXMP("0.1") DOC_END
KV_SERIALIZE_CUSTOM(rate_up_limit, std::string, bc_services::transform_double_to_string, bc_services::transform_string_to_double) DOC_DSCR("Upper limit for the rate") DOC_EXMP("0.1") DOC_END
KV_SERIALIZE(payment_types) DOC_DSCR("Types of payment accepted for the offers(in a free form as it is in contract)") DOC_END
KV_SERIALIZE(location_country) DOC_DSCR("Country of the location for the offers") DOC_END
KV_SERIALIZE(location_city) DOC_DSCR("City of the location for the offers") DOC_END
KV_SERIALIZE(target) DOC_DSCR("Target entity of the offers") DOC_END
KV_SERIALIZE(primary) DOC_DSCR("Primary field for the offers") DOC_END
KV_SERIALIZE(bonus) DOC_DSCR("Bonus associated with the offers") DOC_EXMP(false) DOC_END
KV_SERIALIZE(category) DOC_DSCR("Category of the offers") DOC_END
KV_SERIALIZE(keyword) DOC_DSCR("Keyword for searching offers") DOC_EXMP("tubes") DOC_END
//KV_SERIALIZE(fake) DOC_DSCR("Flag indicating whether the offer is fake") DOC_EXMP() DOC_END
END_KV_SERIALIZE_MAP()
};

View file

@ -1,4 +1,4 @@
// Copyright (c) 2022 Zano Project
// Copyright (c) 2022-2024 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@ -56,7 +56,7 @@ namespace currency
bool found = false;
if (this->zarcanum /* && td.is_zc() */)
if (this->zarcanum)
{
crypto::mp::uint256_t lhs;
crypto::mp::uint512_t rhs;
@ -70,7 +70,7 @@ namespace currency
const boost::multiprecision::uint256_t d_mp = lhs / (crypto::c_zarcanum_z_coeff_mp * this->stake_amount) + 1;
const boost::multiprecision::uint256_t ba = d_mp * crypto::c_zarcanum_z_coeff_mp * this->stake_amount - lhs;
const boost::multiprecision::uint256_t l_div_z_D = this->z_l_div_z_D / crypto::c_zarcanum_z_coeff_mp;
LOG_PRINT_GREEN("Found Zarcanum kernel: amount: " << currency::print_money_brief(this->stake_amount) << /* ", gindex: " << td.m_global_output_index << */ ENDL
LOG_PRINT_GREEN("Found Zarcanum kernel: amount: " << currency::print_money_brief(this->stake_amount) << ENDL
<< "difficulty: " << this->basic_diff << ENDL
<< "kernel info: " << ENDL
<< print_stake_kernel_info(this->sk)
@ -78,9 +78,8 @@ namespace currency
<< "lhs: 0x" << crypto::scalar_t(lhs).to_string_as_hex_number() << " = 0x" << std::hex << d_mp << " * 2^64 * " << this->stake_amount << " - 0x" << std::hex << ba << ENDL
<< "rhs: 0x" << crypto::scalar_t(rhs).to_string_as_hex_number() << ENDL
<< "d: 0x" << std::hex << d_mp << ENDL
<< "l / floor(z * D): 0x" << std::hex << l_div_z_D
<< "floor(l / z * D): 0x" << std::hex << l_div_z_D
, LOG_LEVEL_0);
}
}
else

View file

@ -60,7 +60,7 @@ namespace currency
return false;
}
if (!check_money_overflow(tx))
if (!check_bare_money_overflow(tx))
{
LOG_PRINT_RED_L0("tx has money overflow, rejected for tx id= " << get_transaction_hash(tx));
return false;

View file

@ -57,7 +57,7 @@ namespace currency
std::stringstream ss;
ss << "\"blocks\":{" << ENDL << print_complete_block_entry_list(v.blocks) << ENDL << "}, " << ENDL;
ss << "\"missed_ids\":" << ENDL;
::epee::serialization::dump_as_json(ss, v.missed_ids, 2);
::epee::serialization::recursive_visitor<::epee::serialization::strategy_json>::dump_as_(ss, v.missed_ids, 2);
ss << ENDL << "\"current_blockchain_height\":" << v.current_blockchain_height;
return ss.str();
}

View file

@ -171,6 +171,11 @@ namespace currency
return true;
}
if(hshd.top_id == currency::null_hash)
{
LOG_PRINT_L0("wtf");
}
int64_t diff = static_cast<int64_t>(hshd.current_height) - static_cast<int64_t>(m_core.get_current_blockchain_size());
LOG_PRINT_COLOR2(LOG_DEFAULT_TARGET, (is_inital ? "Inital ":"Idle ") << "sync data returned unknown top block (" << hshd.top_id << "): " << m_core.get_top_block_height() << " -> " << hshd.current_height - 1
<< " [" << std::abs(diff) << " blocks (" << diff / (24 * 60 * 60 / DIFFICULTY_TOTAL_TARGET ) << " days) "

View file

@ -155,7 +155,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, command_line::arg_log_level);
command_line::add_arg(desc_cmd_sett, command_line::arg_console);
command_line::add_arg(desc_cmd_only, command_line::arg_show_details);
command_line::add_arg(desc_cmd_only, command_line::arg_show_rpc_autodoc);
command_line::add_arg(desc_cmd_only, command_line::arg_generate_rpc_autodoc);
command_line::add_arg(desc_cmd_sett, command_line::arg_disable_stop_if_time_out_of_sync);
command_line::add_arg(desc_cmd_sett, command_line::arg_disable_stop_on_low_free_space);
command_line::add_arg(desc_cmd_sett, command_line::arg_enable_offers_service);
@ -272,21 +272,15 @@ int main(int argc, char* argv[])
if (stratum_enabled)
stratum_server_ptr = std::make_shared<currency::stratum_server>(&ccore);
if (command_line::get_arg(vm, command_line::arg_show_rpc_autodoc))
{
LOG_PRINT_L0("Dumping RPC auto-generated documents!");
epee::net_utils::http::http_request_info query_info;
epee::net_utils::http::http_response_info response_info;
epee::net_utils::connection_context_base conn_context;
std::string generate_reference = std::string("RPC_COMMANDS_LIST:\n");
bool call_found = false;
rpc_server.handle_http_request_map(query_info, response_info, conn_context, call_found, generate_reference);
std::string json_rpc_reference;
query_info.m_URI = JSON_RPC_REFERENCE_MARKER;
query_info.m_body = "{\"jsonrpc\": \"2.0\", \"method\": \"nonexisting_method\", \"params\": {}},";
rpc_server.handle_http_request_map(query_info, response_info, conn_context, call_found, json_rpc_reference);
LOG_PRINT_L0(generate_reference << ENDL << "----------------------------------------" << ENDL << json_rpc_reference);
if (command_line::has_arg(vm, command_line::arg_generate_rpc_autodoc))
{
std::string path_to_generate = command_line::get_arg(vm, command_line::arg_generate_rpc_autodoc);
if (!generate_doc_as_md_files(path_to_generate, rpc_server))
return 1;
return 0;
}
bool res = false;

View file

@ -223,7 +223,7 @@ QString MainWindow::get_default_user_dir(const QString& param)
}
bool MainWindow::toggle_mining()
bool MainWindow::toggle_mining(const QString& param)
{
TRY_ENTRY();
m_backend.toggle_pos_mining();
@ -238,7 +238,7 @@ QString MainWindow::get_exchange_last_top(const QString& params)
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_tx_pool_info()
QString MainWindow::get_tx_pool_info(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -248,7 +248,7 @@ QString MainWindow::get_tx_pool_info()
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::request_dummy()
QString MainWindow::request_dummy(const QString& param)
{
static int code_ = 0;
TRY_ENTRY();
@ -284,7 +284,7 @@ QString MainWindow::call_rpc(const QString& params)
epee::net_utils::http::http_request_info query_info = AUTO_VAL_INIT(query_info);
epee::net_utils::http::http_response_info response_info = AUTO_VAL_INIT(response_info);
currency::core_rpc_server::connection_context dummy_context = AUTO_VAL_INIT(dummy_context);
currency::core_rpc_server::connection_context dummy_context(RPC_INTERNAL_UI_CONTEXT, 0, 0, true);
query_info.m_URI = "/json_rpc";
query_info.m_body = params.toStdString();
@ -301,14 +301,34 @@ QString MainWindow::call_rpc(const QString& params)
return QString::fromStdString(response_info.m_body);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_default_fee()
QString MainWindow::call_wallet_rpc(const QString& wallet_id_str, const QString& params)
{
TRY_ENTRY();
if (!m_backend.is_core_initialized())
{
epee::json_rpc::error_response rsp;
rsp.jsonrpc = "2.0";
rsp.error.code = -1;
rsp.error.message = API_RETURN_CODE_CORE_BUSY;
return QString::fromStdString(epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp)));
}
uint64_t wallet_id = std::stoull(wallet_id_str.toStdString());
return QString::fromStdString(m_backend.invoke(wallet_id, params.toStdString()));
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_default_fee(const QString& param)
{
TRY_ENTRY();
return QString(std::to_string(m_backend.get_default_fee()).c_str());
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_options()
QString MainWindow::get_options(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -319,7 +339,7 @@ QString MainWindow::get_options()
CATCH_ENTRY_FAIL_API_RESPONCE();
}
void MainWindow::tray_quit_requested()
void MainWindow::tray_quit_requested(const QString& param)
{
TRY_ENTRY();
LOG_PRINT_MAGENTA("[GUI]->[HTML] tray_quit_requested", LOG_LEVEL_0);
@ -350,10 +370,10 @@ void MainWindow::closeEvent(QCloseEvent *event)
}
else
{
event->ignore();
//m_quit_requested = true;
LOG_PRINT_L0("[GUI]->[HTML] quit_requested");
emit quit_requested("{}");
event->ignore();
}
CATCH_ENTRY2(void());
}
@ -474,7 +494,7 @@ bool MainWindow::init(const std::string& html_path)
CATCH_ENTRY2(false);
}
void MainWindow::on_menu_show()
void MainWindow::on_menu_show(const QString& param)
{
TRY_ENTRY();
qDebug() << "Context menu: show()";
@ -546,7 +566,7 @@ void MainWindow::bool_toggle_icon(const QString& param)
CATCH_ENTRY2(void());
}
QString MainWindow::get_log_file()
QString MainWindow::get_log_file(const QString& param)
{
TRY_ENTRY();
std::string buff;
@ -662,7 +682,7 @@ QString MainWindow::set_clipboard(const QString& param)
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::get_clipboard()
QString MainWindow::get_clipboard(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -671,7 +691,7 @@ QString MainWindow::get_clipboard()
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::on_request_quit()
QString MainWindow::on_request_quit(const QString& param)
{
TRY_ENTRY();
LOG_PRINT_MAGENTA("[HTML]->[GUI] on_request_quit", LOG_LEVEL_0);
@ -933,7 +953,7 @@ bool MainWindow::init_backend(int argc, char* argv[])
CATCH_ENTRY2(false);
}
QString MainWindow::is_remnotenode_mode_preconfigured()
QString MainWindow::is_remnotenode_mode_preconfigured(const QString& param)
{
TRY_ENTRY();
return API_RETURN_CODE_FALSE;
@ -997,11 +1017,11 @@ bool MainWindow::update_wallet_status(const view::wallet_status_info& wsi)
m_wallet_states->operator [](wsi.wallet_id) = wsi.wallet_state;
std::string json_str_pub;
epee::serialization::store_t_to_json(static_cast<const view::wallet_status_info_base&>(wsi), json_str_pub, 0, epee::serialization::eol_lf);
epee::serialization::store_t_to_json(static_cast<const view::wallet_status_info_base&>(wsi), json_str_pub, 0);
LOG_PRINT_L0(get_wallet_log_prefix(wsi.wallet_id) + "SENDING SIGNAL -> [update_wallet_status]:" << std::endl << json_str_pub);
std::string json_str;
epee::serialization::store_t_to_json(wsi, json_str, 0, epee::serialization::eol_lf);
epee::serialization::store_t_to_json(wsi, json_str, 0);
QMetaObject::invokeMethod(this, "update_wallet_status", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
return true;
CATCH_ENTRY2(false);
@ -1011,7 +1031,7 @@ bool MainWindow::set_options(const view::gui_options& opt)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(opt, json_str, 0, epee::serialization::eol_lf);
epee::serialization::store_t_to_json(opt, json_str, 0);
LOG_PRINT_L0("SENDING SIGNAL -> [set_options]:" << std::endl << json_str);
QMetaObject::invokeMethod(this, "set_options", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
return true;
@ -1022,7 +1042,7 @@ bool MainWindow::update_tor_status(const view::current_action_status& opt)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(opt, json_str, 0, epee::serialization::eol_lf);
epee::serialization::store_t_to_json(opt, json_str, 0);
LOG_PRINT_L0("SENDING SIGNAL -> [HANDLE_CURRENT_ACTION_STATE]:" << std::endl << json_str);
QMetaObject::invokeMethod(this, "handle_current_action_state", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
return true;
@ -1044,7 +1064,7 @@ bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, l
CATCH_ENTRY2(false);
}
bool MainWindow::get_is_disabled_notifications()
bool MainWindow::get_is_disabled_notifications(const QString& param)
{
return m_config.disable_notifications;
}
@ -1067,7 +1087,7 @@ bool MainWindow::update_wallets_info(const view::wallets_summary_info& wsi)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(wsi, json_str, 0, epee::serialization::eol_lf);
epee::serialization::store_t_to_json(wsi, json_str, 0);
LOG_PRINT_L0("SENDING SIGNAL -> [update_wallets_info]"<< std::endl << json_str );
QMetaObject::invokeMethod(this, "update_wallets_info", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str()));
@ -1079,7 +1099,7 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(tei, json_str, 0, epee::serialization::eol_lf);
epee::serialization::store_t_to_json(tei, json_str, 0);
LOG_PRINT_L0(get_wallet_log_prefix(tei.wallet_id) + "SENDING SIGNAL -> [money_transfer]" << std::endl << json_str);
//this->money_transfer(json_str.c_str());
@ -1134,7 +1154,7 @@ bool MainWindow::money_transfer_cancel(const view::transfer_event_info& tei)
{
TRY_ENTRY();
std::string json_str;
epee::serialization::store_t_to_json(tei, json_str, 0, epee::serialization::eol_lf);
epee::serialization::store_t_to_json(tei, json_str, 0);
LOG_PRINT_L0(get_wallet_log_prefix(tei.wallet_id) + "SENDING SIGNAL -> [money_transfer_cancel]");
//this->money_transfer_cancel(json_str.c_str());
@ -1149,7 +1169,7 @@ bool MainWindow::wallet_sync_progress(const view::wallet_sync_progres_param& p)
TRY_ENTRY();
LOG_PRINT_L2(get_wallet_log_prefix(p.wallet_id) + "SENDING SIGNAL -> [wallet_sync_progress]" << " wallet_id: " << p.wallet_id << ": " << p.progress << "%");
//this->wallet_sync_progress(epee::serialization::store_t_to_json(p).c_str());
QMetaObject::invokeMethod(this, "wallet_sync_progress", Qt::QueuedConnection, Q_ARG(QString, epee::serialization::store_t_to_json(p, 0, epee::serialization::eol_lf).c_str()));
QMetaObject::invokeMethod(this, "wallet_sync_progress", Qt::QueuedConnection, Q_ARG(QString, epee::serialization::store_t_to_json(p, 0).c_str()));
return true;
CATCH_ENTRY2(false);
}
@ -1181,21 +1201,21 @@ bool MainWindow::pos_block_found(const currency::block& block_found)
CATCH_ENTRY2(false);
}
QString MainWindow::get_version()
QString MainWindow::get_version(const QString& param)
{
TRY_ENTRY();
return PROJECT_VERSION_LONG;
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_os_version()
QString MainWindow::get_os_version(const QString& param)
{
TRY_ENTRY();
return tools::get_os_version_string().c_str();
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::get_network_type()
QString MainWindow::get_network_type(const QString& param)
{
#if defined(TESTNET)
return "testnet";
@ -1211,7 +1231,7 @@ QString MainWindow::get_alias_coast(const QString& param)
PREPARE_ARG_FROM_JSON(currency::struct_with_one_t_type<std::string>, lvl);
view::get_alias_coast_response resp;
resp.error_code = m_backend.get_alias_coast(lvl.v, resp.coast);
return epee::serialization::store_t_to_json(resp, 0, epee::serialization::eol_lf).c_str();
return epee::serialization::store_t_to_json(resp, 0).c_str();
CATCH_ENTRY_FAIL_API_RESPONCE();
}
@ -1239,7 +1259,7 @@ QString MainWindow::set_localization_strings(const QString param)
resp.error_code = API_RETURN_CODE_OK;
LOG_PRINT_L0("New localization set, language title: " << lr.language_title << ", strings " << lr.strings.size());
}
return epee::serialization::store_t_to_json(resp, 0, epee::serialization::eol_lf).c_str();
return epee::serialization::store_t_to_json(resp, 0).c_str();
CATCH_ENTRY_FAIL_API_RESPONCE();
}
@ -1408,7 +1428,7 @@ void MainWindow::on_clear_events()
}
QString MainWindow::store_secure_app_data(const QString& param)
QString MainWindow::store_secure_app_data(const QString& param, const QString& password)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -1626,7 +1646,7 @@ QString MainWindow::load_from_file(const QString& path)
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::get_app_data()
QString MainWindow::get_app_data(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -1637,7 +1657,7 @@ QString MainWindow::get_app_data()
}
QString MainWindow::have_secure_app_data()
QString MainWindow::have_secure_app_data(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -1655,7 +1675,7 @@ QString MainWindow::have_secure_app_data()
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::drop_secure_app_data()
QString MainWindow::drop_secure_app_data(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -1673,7 +1693,7 @@ QString MainWindow::drop_secure_app_data()
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_all_aliases()
QString MainWindow::get_all_aliases(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -1779,7 +1799,7 @@ QString MainWindow::set_enable_tor(const QString& param)
// return MAKE_RESPONSE(ar);
// }
QString MainWindow::webkit_launched_script()
QString MainWindow::webkit_launched_script(const QString& param)
{
TRY_ENTRY();
m_last_update_daemon_status_json.clear();
@ -1795,7 +1815,7 @@ QString MainWindow::show_openfile_dialog(const QString& param)
if (!epee::serialization::load_t_from_json(ofdr, param.toStdString()))
{
ofdres.error_code = API_RETURN_CODE_BAD_ARG;
return epee::serialization::store_t_to_json(ofdres, 0, epee::serialization::eol_lf).c_str();
return epee::serialization::store_t_to_json(ofdres, 0).c_str();
}
QString path = QFileDialog::getOpenFileName(this, ofdr.caption.c_str(),
@ -1805,7 +1825,7 @@ QString MainWindow::show_openfile_dialog(const QString& param)
if (!path.length())
{
ofdres.error_code = API_RETURN_CODE_CANCELED;
return epee::serialization::store_t_to_json(ofdres, 0, epee::serialization::eol_lf).c_str();
return epee::serialization::store_t_to_json(ofdres, 0).c_str();
}
ofdres.error_code = API_RETURN_CODE_OK;
@ -1828,7 +1848,7 @@ QString MainWindow::show_savefile_dialog(const QString& param)
if (!path.length())
{
ofdres.error_code = API_RETURN_CODE_CANCELED;
return epee::serialization::store_t_to_json(ofdres, 0, epee::serialization::eol_lf).c_str();
return epee::serialization::store_t_to_json(ofdres, 0).c_str();
}
ofdres.error_code = API_RETURN_CODE_OK;
@ -1993,7 +2013,7 @@ QString MainWindow::get_fav_offers(const QString& param)
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::is_pos_allowed()
QString MainWindow::is_pos_allowed(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -2265,7 +2285,7 @@ QString MainWindow::is_wallet_password_valid(const QString& param)
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::is_autostart_enabled()
QString MainWindow::is_autostart_enabled(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
@ -2319,6 +2339,16 @@ QString MainWindow::open_url_in_browser(const QString& param)
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::setup_jwt_wallet_rpc(const QString& param)
{
TRY_ENTRY();
m_backend.setup_wallet_rpc(param.toStdString());
return API_RETURN_CODE_OK;
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
QString MainWindow::is_valid_restore_wallet_text(const QString& param)
{
TRY_ENTRY();

View file

@ -106,17 +106,18 @@ public:
QString accept_cancel_contract(const QString& param);
QString get_version();
QString get_os_version();
QString get_network_type();
QString on_request_quit(const QString& param);
QString get_version(const QString& param);
QString get_os_version(const QString& param);
QString get_network_type(const QString& param);
QString transfer(const QString& json_transfer_object);
QString have_secure_app_data();
QString drop_secure_app_data();
QString have_secure_app_data(const QString& param);
QString drop_secure_app_data(const QString& param);
QString get_secure_app_data(const QString& param);
QString store_secure_app_data(const QString& param);
QString store_secure_app_data(const QString& param, const QString& password);
QString set_master_password(const QString& param);
QString check_master_password(const QString& param);
QString get_app_data();
QString get_app_data(const QString& param);
QString store_app_data(const QString& param);
QString get_default_user_dir(const QString& param);
// QString get_all_offers(const QString& param);
@ -126,12 +127,11 @@ public:
QString push_update_offer(const QString& param);
QString get_alias_info_by_address(const QString& param);
QString get_alias_info_by_name(const QString& param);
QString get_all_aliases();
QString get_all_aliases(const QString& param);
QString request_alias_registration(const QString& param);
QString request_alias_update(const QString& param);
QString get_alias_coast(const QString& param);
QString validate_address(const QString& param);
QString on_request_quit();
QString resync_wallet(const QString& param);
QString get_recent_transfers(const QString& param);
QString get_mining_history(const QString& param);
@ -141,11 +141,11 @@ public:
QString get_log_level(const QString& param);
QString set_enable_tor(const QString& param);
// QString dump_all_offers();
QString webkit_launched_script();
QString webkit_launched_script(const QString& param);
QString get_smart_wallet_info(const QString& param);
QString restore_wallet(const QString& param);
QString use_whitelisting(const QString& param);
QString is_pos_allowed();
QString is_pos_allowed(const QString& param);
QString store_to_file(const QString& path, const QString& buff);
QString load_from_file(const QString& path);
QString is_file_exist(const QString& path);
@ -153,7 +153,7 @@ public:
QString backup_wallet_keys(const QString& obj);
QString reset_wallet_password(const QString& param);
QString is_wallet_password_valid(const QString& param);
QString is_autostart_enabled();
QString is_autostart_enabled(const QString& param);
QString toggle_autostart(const QString& param);
QString is_valid_restore_wallet_text(const QString& param);
QString get_seed_phrase_info(const QString& param);
@ -161,13 +161,13 @@ public:
QString print_log(const QString& param);
QString set_clipboard(const QString& param);
QString set_localization_strings(const QString str);
QString get_clipboard();
QString get_clipboard(const QString& param);
void message_box(const QString& msg);
bool toggle_mining();
bool toggle_mining(const QString& param);
QString get_exchange_last_top(const QString& params);
QString get_tx_pool_info();
QString get_default_fee();
QString get_options();
QString get_tx_pool_info(const QString& param);
QString get_default_fee(const QString& param);
QString get_options(const QString& param);
void bool_toggle_icon(const QString& param);
QString add_custom_asset_id(const QString& param);
QString remove_custom_asset_id(const QString& param);
@ -177,26 +177,28 @@ public:
QString get_ionic_swap_proposal_info(const QString& param);
QString accept_ionic_swap_proposal(const QString& param);
bool get_is_disabled_notifications();
bool get_is_disabled_notifications(const QString& param);
bool set_is_disabled_notifications(const bool& param);
QString export_wallet_history(const QString& param);
QString get_log_file();
QString get_log_file(const QString& param);
//QString check_available_sources(const QString& param);
QString open_url_in_browser(const QString& param);
QString setup_jwt_wallet_rpc(const QString& param);
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
void tray_quit_requested();
void on_menu_show();
QString is_remnotenode_mode_preconfigured();
void tray_quit_requested(const QString& param);
void on_menu_show(const QString& param);
QString is_remnotenode_mode_preconfigured(const QString& param);
QString start_backend(const QString& params);
QString async_call(const QString& func_name, const QString& params);
QString sync_call(const QString& func_name, const QString& params);
//for test purposes onlys
QString request_dummy();
//for test purposes only
QString request_dummy(const QString& param);
QString call_rpc(const QString& params);
QString call_wallet_rpc(const QString& wallet_id, const QString& params);
signals:
void quit_requested(const QString str);

@ -1 +1 @@
Subproject commit f8e9556fbaccd49841ce91afc3c90c8e3142ac95
Subproject commit 9be6a53f757a17403ea5798d08b577d450eb620a

View file

@ -176,7 +176,7 @@ namespace currency
res.pow_sequence_factor = m_core.get_blockchain_storage().get_current_sequence_factor(false);
if (req.flags&(COMMAND_RPC_GET_INFO_FLAG_POS_DIFFICULTY | COMMAND_RPC_GET_INFO_FLAG_TOTAL_COINS))
{
res.block_reward = currency::get_base_block_reward(true, total_coins, res.height);
res.block_reward = currency::get_base_block_reward(res.height);
currency::block b = AUTO_VAL_INIT(b);
m_core.get_blockchain_storage().get_top_block(b);
res.last_block_total_reward = currency::get_reward_from_miner_tx(b.miner_tx);
@ -738,6 +738,18 @@ namespace currency
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_assets_list(const COMMAND_RPC_GET_ASSETS_LIST::request& req, COMMAND_RPC_GET_ASSETS_LIST::response& res, connection_context& cntx)
{
CHECK_CORE_READY();
if (!m_core.get_blockchain_storage().get_assets(req.offset, req.count, res.assets))
{
res.status = API_RETURN_CODE_NOT_FOUND;
return true;
}
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
{
if (!m_core.get_blockchain_storage().get_main_block_rpc_details(req.id, res.block_details))

View file

@ -88,6 +88,7 @@ namespace currency
bool on_get_pool_info(const COMMAND_RPC_GET_POOL_INFO::request& req, COMMAND_RPC_GET_POOL_INFO::response& res, connection_context& cntx);
bool on_get_votes(const COMMAND_RPC_GET_VOTES::request& req, COMMAND_RPC_GET_VOTES::response& res, connection_context& cntx);
bool on_get_asset_info(const COMMAND_RPC_GET_ASSET_INFO::request& req, COMMAND_RPC_GET_ASSET_INFO::response& res, connection_context& cntx);
bool on_get_assets_list(const COMMAND_RPC_GET_ASSETS_LIST::request& req, COMMAND_RPC_GET_ASSETS_LIST::response& res, connection_context& cntx);
bool on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
bool on_get_alt_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
@ -150,7 +151,8 @@ namespace currency
MAP_JON_RPC ("getrandom_outs3", on_get_random_outs3, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3)
MAP_JON_RPC ("get_votes", on_get_votes, COMMAND_RPC_GET_VOTES)
//assets api
MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO)
MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO)
MAP_JON_RPC ("get_assets_list", on_get_assets_list, COMMAND_RPC_GET_ASSETS_LIST)
MAP_JON_RPC_WE("get_main_block_details", on_get_main_block_details, COMMAND_RPC_GET_BLOCK_DETAILS)
MAP_JON_RPC_WE("get_alt_block_details", on_get_alt_block_details, COMMAND_RPC_GET_BLOCK_DETAILS)

File diff suppressed because it is too large Load diff

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
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -63,6 +63,11 @@ namespace tools
}
bool password_container::read_password(const std::string& prompt_text)
{
return read_input(prompt_text, '*');
}
bool password_container::read_input(const std::string& prompt_text, char char_to_replace_user_input /* = '\0' */)
{
clear();
@ -70,7 +75,7 @@ namespace tools
if (is_cin_tty())
{
std::cout << prompt_text;
r = read_from_tty();
r = read_from_tty(char_to_replace_user_input);
}
else
{
@ -122,7 +127,7 @@ namespace tools
}
}
bool password_container::read_from_tty()
bool password_container::read_from_tty(char char_to_replace_user_input)
{
const char BACKSPACE = 8;
@ -162,7 +167,7 @@ namespace tools
else
{
m_password.push_back(ch);
std::cout << '*';
std::cout << (char_to_replace_user_input != '\0' ? char_to_replace_user_input : ch);
}
}
@ -198,7 +203,7 @@ namespace tools
}
}
bool password_container::read_from_tty()
bool password_container::read_from_tty(char char_to_replace_user_input)
{
const char BACKSPACE = 127;
@ -227,7 +232,7 @@ namespace tools
else
{
m_password.push_back(ch);
std::cout << '*';
std::cout << (char_to_replace_user_input != '\0' ? char_to_replace_user_input : ch);
}
}

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
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -24,13 +24,15 @@ namespace tools
void clear();
bool empty() const { return m_empty; }
const std::string& password() const { return m_password; }
const std::string& get_input() const { return m_password; } // TODO: refactor this
void password(std::string&& val) { m_password = std::move(val); m_empty = false; }
bool read_password();
bool read_password(const std::string& prompt_text);
bool read_input(const std::string& prompt_text, char char_to_replace_user_input = '\0');
private:
bool read_from_file();
bool read_from_tty();
bool read_from_tty(char char_to_replace_user_input);
private:
bool m_empty;

View file

@ -290,7 +290,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, ph::_1), "start_mining <threads_count> - Start mining in daemon");
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon");
m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, ph::_1), "Resynchronize transactions and balance");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "Show current wallet balance");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "[force_all] Show current wallet balance, with 'force_all' param it displays all assets without filtering against whitelists");
m_cmd_binder.set_handler("show_staking_history", boost::bind(&simple_wallet::show_staking_history, this, ph::_1), "show_staking_history [2] - Show staking transfers, if option provided - number of days for history to display");
m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, ph::_1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability");
m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, ph::_1), "incoming_transfers counts");
@ -315,6 +315,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this,ph::_1), "Rescan transfers for key image");
m_cmd_binder.set_handler("print_utxo_distribution", boost::bind(&simple_wallet::print_utxo_distribution, this,ph::_1), "Prints utxo distribution");
m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this,ph::_1), "sweep_below <mixin_count> <address> <amount_lower_limit> [payment_id] - Tries to transfers all coins with amount below the given limit to the given address");
m_cmd_binder.set_handler("sweep_bare_outs", boost::bind(&simple_wallet::sweep_bare_outs, this,ph::_1), "sweep_bare_outs - Transfers all bare unspent outputs to itself. Uses several txs if necessary.");
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this,ph::_1), "Show current wallet public address");
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::integrated_address, this,ph::_1), "integrated_address [<payment_id>|<integrated_address] - encodes given payment_id along with wallet's address into an integrated address (random payment_id will be used if none is provided). Decodes given integrated_address into standard address");
@ -542,8 +543,7 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_
m_restore_wallet = command_line::get_arg(vm, arg_restore_wallet);
m_disable_tor = command_line::get_arg(vm, arg_disable_tor_relay);
m_voting_config_file = command_line::get_arg(vm, arg_voting_config_file);
m_no_password_confirmations = command_line::get_arg(vm, arg_no_password_confirmations);
m_no_password_confirmations = command_line::get_arg(vm, arg_no_password_confirmations);
}
//----------------------------------------------------------------------------------------------------
@ -1001,9 +1001,16 @@ bool simple_wallet::refresh(const std::vector<std::string>& args)
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::show_balance(const std::vector<std::string>& args/* = std::vector<std::string>()*/)
bool simple_wallet::show_balance(const std::vector<std::string>& args /* = std::vector<std::string>()*/)
{
success_msg_writer() << m_wallet->get_balance_str();
if (args.size() == 1 && args[0] == "raw")
{
success_msg_writer() << m_wallet->get_balance_str_raw();
}
else
{
success_msg_writer() << m_wallet->get_balance_str();
}
return true;
}
//----------------------------------------------------------------------------------------------------
@ -2511,8 +2518,129 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args)
SIMPLE_WALLET_CATCH_TRY_ENTRY();
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_bare_outs(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
bool r = false;
if (args.size() > 1)
{
fail_msg_writer() << "Invalid number of agruments given";
return true;
}
currency::account_public_address target_address = m_wallet->get_account().get_public_address();
currency::payment_id_t integrated_payment_id{};
if (args.size() == 1)
{
if (!m_wallet->get_transfer_address(args[0], target_address, integrated_payment_id))
{
fail_msg_writer() << "Unable to parse address from " << args[1];
return true;
}
if (!integrated_payment_id.empty())
{
fail_msg_writer() << "Payment id is not supported. Please, don't use integrated address with this command.";
return true;
}
}
if (!m_wallet->has_bare_unspent_outputs())
{
success_msg_writer(true) << "This wallet doesn't have bare unspent outputs.\nNothing to do. Everything looks good.";
return true;
}
std::vector<tools::wallet2::batch_of_bare_unspent_outs> groups;
m_wallet->get_bare_unspent_outputs_stats(groups);
if (groups.empty())
{
uint64_t unlocked_balance = 0;
uint64_t balance = m_wallet->balance(unlocked_balance);
if (balance < COIN)
success_msg_writer(false) << "Looks like it's not enough coins to perform this operation. Transferring " << print_money_brief(TX_MINIMUM_FEE) << " ZANO or more to this wallet may help.";
else if (unlocked_balance < COIN)
success_msg_writer(false) << "Not enough spendable outputs to perform this operation. Please, try again later.";
else
{
success_msg_writer(false) << "This operation couldn't be performed for some reason. Please, copy simplewallet's log file and ask for support. Nothing was done.";
LOG_PRINT_L0("strange situation: balance: " << print_money_brief(balance) << ", unlocked_balance: " << print_money_brief(unlocked_balance) << " but get_bare_unspent_outputs_stats returned empty result");
}
return true;
}
size_t i = 0, total_bare_outs = 0;
uint64_t total_amount = 0;
std::stringstream details_ss;
for(auto &g : groups)
{
details_ss << std::setw(2) << i << ": ";
for (auto& tid: g.tids)
{
tools::transfer_details td{};
CHECK_AND_ASSERT_THROW_MES(m_wallet->get_transfer_info_by_index(tid, td), "get_transfer_info_by_index failed with index " << tid);
details_ss << tid << " (" << print_money_brief(td.m_amount) << "), ";
total_amount += td.m_amount;
}
if (g.additional_tid)
details_ss << "additional tid: " << g.tids.back() << "( " << print_money_brief(g.additional_tid_amount) << ")";
else
details_ss.seekp(-2, std::ios_base::end);
details_ss << ENDL;
++i;
total_bare_outs += g.tids.size();
}
LOG_PRINT_L1("bare UTXO:" << ENDL << details_ss.str());
success_msg_writer(true) << "This wallet contains " << total_bare_outs << " bare outputs with total amount of " << print_money_brief(total_amount) <<
". They can be converted in " << groups.size() << " transaction" << (groups.size() > 1 ? "s" : "") << ", with total fee = " << print_money_brief(TX_DEFAULT_FEE * i) << ".";
if (target_address != m_wallet->get_account().get_public_address())
message_writer(epee::log_space::console_color_yellow, false) << print_money_brief(total_amount) << " coins will be sent to address " << get_account_address_as_str(target_address);
tools::password_container reader;
if (!reader.read_input("Would you like to continue? (y/yes/n/no):\n") || (reader.get_input() != "y" && reader.get_input() != "yes"))
{
success_msg_writer(false) << "Operatation terminated as requested by user.";
return true;
}
size_t total_tx_sent = 0;
uint64_t total_fee_spent = 0;
uint64_t total_amount_sent = 0;
auto on_tx_sent_callback = [&](size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err) {
auto mw = success_msg_writer(false);
mw << std::setw(2) << batch_index << ": transaction ";
if (!sent_ok)
{
mw << "failed (" << err << ")";
return;
}
mw << get_transaction_hash(tx) << ", fee: " << print_money_brief(fee) << ", amount: " << print_money_brief(amount);
++total_tx_sent;
total_fee_spent += fee;
total_amount_sent += amount;
};
if (!m_wallet->sweep_bare_unspent_outputs(target_address, groups, on_tx_sent_callback))
{
auto mw = fail_msg_writer();
mw << "Operatation failed.";
if (total_tx_sent > 0)
mw << " However, " << total_tx_sent << " transaction" << (total_tx_sent == 1 ? " was" : "s were") << " successfully sent, " << print_money_brief(total_amount_sent) << " coins transferred, and " << print_money_brief(total_fee_spent) << " was spent for fees.";
}
else
{
success_msg_writer(true) << "Operatation succeeded. " << ENDL << total_tx_sent << " transaction" << (total_tx_sent == 1 ? " was" : "s were") << " successfully sent, " << print_money_brief(total_amount_sent) << " coins transferred, and " << print_money_brief(total_fee_spent) << " was spent for fees.";
}
SIMPLE_WALLET_CATCH_TRY_ENTRY();
return true;
}
//----------------------------------------------------------------------------------------------------
uint64_t
get_tick_count__()
@ -2679,9 +2807,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_set_timeout);
command_line::add_arg(desc_params, arg_voting_config_file);
command_line::add_arg(desc_params, arg_no_password_confirmations);
command_line::add_arg(desc_params, command_line::arg_generate_rpc_autodoc);
tools::wallet_rpc_server::init_options(desc_params);
@ -2736,6 +2862,16 @@ int main(int argc, char* argv[])
message_writer(epee::log_space::console_color_white, true) << "Log level changed: " << old_log_level << " -> " << new_log_level;
}
if (command_line::has_arg(vm, command_line::arg_generate_rpc_autodoc))
{
tools::wallet_rpc_server wallet_rpc_server(std::shared_ptr<tools::wallet2>(new tools::wallet2()));
std::string path_to_generate = command_line::get_arg(vm, command_line::arg_generate_rpc_autodoc);
if (!generate_doc_as_md_files(path_to_generate, wallet_rpc_server))
return 1;
return 0;
}
if (command_line::has_arg(vm, arg_scan_for_wallet))
{
@ -2816,6 +2952,22 @@ int main(int argc, char* argv[])
break;
}
//try to sync it
struct wallet_rpc_local_callback : public tools::i_wallet2_callback
{
std::shared_ptr<tools::wallet2> m_wlt_ptr;
wallet_rpc_local_callback(std::shared_ptr<tools::wallet2> ptr): m_wlt_ptr(ptr)
{}
virtual void on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets)
{
wallets.push_back(tools::wallet_public::wallet_entry_info());
wallets.back().wallet_id = 0;
tools::get_wallet_info(*m_wlt_ptr, wallets.back().wi);
}
};
std::shared_ptr<tools::i_wallet2_callback> callback(new wallet_rpc_local_callback(wallet_ptr));
while (true)
{
try
@ -2828,6 +2980,7 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
wal.set_use_assets_whitelisting(true);
wal.callback(callback);
if (!offline_mode)
wal.refresh();

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
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -87,6 +87,7 @@ namespace currency
bool sign_transfer(const std::vector<std::string> &args);
bool submit_transfer(const std::vector<std::string> &args);
bool sweep_below(const std::vector<std::string> &args);
bool sweep_bare_outs(const std::vector<std::string> &args);
bool tor_enable(const std::vector<std::string> &args);
bool tor_disable(const std::vector<std::string> &args);
bool deploy_new_asset(const std::vector<std::string> &args);

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 300
#define PROJECT_VERSION_BUILD_NO 317
#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

@ -51,6 +51,27 @@ namespace tools
return r;
}
//------------------------------------------------------------------------------------------------------------------------------
bool default_http_core_proxy::call_COMMAND_RPC_INVOKE(const std::string& uri, const std::string& body, int& response_code, std::string& response_body)
{
return call_request([&]() {
#ifdef MOBILE_WALLET_BUILD
LOG_PRINT_L0("[INVOKE_PROXY] ---> " << uri)
#endif
const epee::net_utils::http::http_response_info* response = nullptr;
bool res = m_http_client.invoke(uri, "POST", body, &response);
if (response)
{
response_body = response->m_body;
response_code = response->m_response_code;
}
#ifdef MOBILE_WALLET_BUILD
LOG_PRINT_L0("[INVOKE_PROXY] <---" << uri)
#endif
return res;
});
}
//------------------------------------------------------------------------------------------------------------------------------
bool default_http_core_proxy::call_COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE(const currency::COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::request& rqt, currency::COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::response& rsp)
{
return invoke_http_json_rpc_update_is_disconnect("get_est_height_from_date", rqt, rsp);

View file

@ -28,7 +28,7 @@ namespace tools
bool set_connection_addr(const std::string& url) override;
void set_connectivity(unsigned int connection_timeout, size_t repeats_count);
void set_connectivity(unsigned int connection_timeout, size_t repeats_count) override;
bool call_COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES(const currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& rqt, currency::COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& rsp) override;
bool call_COMMAND_RPC_GET_BLOCKS_FAST(const currency::COMMAND_RPC_GET_BLOCKS_FAST::request& rqt, currency::COMMAND_RPC_GET_BLOCKS_FAST::response& rsp) override;
bool call_COMMAND_RPC_GET_BLOCKS_DIRECT(const currency::COMMAND_RPC_GET_BLOCKS_DIRECT::request& rqt, currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& rsp) override;
@ -53,6 +53,7 @@ namespace tools
bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res) override;
bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_POOL_INFO::request& req, currency::COMMAND_RPC_GET_POOL_INFO::response& res) override;
bool call_COMMAND_RPC_GET_ASSET_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) override;
bool call_COMMAND_RPC_INVOKE(const std::string& uri, const std::string& body, int& response_code, std::string& response_body) override;
bool check_connection() override;
bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override;

View file

@ -143,6 +143,22 @@ namespace tools
return m_rpc.on_get_asset_info(req, res, m_cntxt_stub);
}
//------------------------------------------------------------------------------------------------------------------------------
virtual bool call_COMMAND_RPC_INVOKE(const std::string& uri, const std::string& body, int& response_code, std::string& response_body) override
{
epee::net_utils::http::http_request_info query_info = AUTO_VAL_INIT(query_info);
query_info.m_URI = uri;
query_info.m_http_method = epee::net_utils::http::http_method_get;
query_info.m_body = body;
epee::net_utils::http::http_response_info response = AUTO_VAL_INIT(response);
epee::net_utils::connection_context_base conn_context = AUTO_VAL_INIT(conn_context);
bool res = m_rpc.handle_http_request(query_info, response, conn_context);
response_body = response.m_body;
response_code = response.m_response_code;
return res;
}
//------------------------------------------------------------------------------------------------------------------------------
virtual bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id) override
{
return tools::get_transfer_address(adr_str, addr, payment_id, this);

View file

@ -53,6 +53,8 @@ namespace tools
virtual bool call_COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN(const currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, currency::COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res){ return false; }
virtual bool call_COMMAND_RPC_GET_POOL_INFO(const currency::COMMAND_RPC_GET_POOL_INFO::request& req, currency::COMMAND_RPC_GET_POOL_INFO::response& res) { return false; }
virtual bool call_COMMAND_RPC_GET_ASSET_INFO(const currency::COMMAND_RPC_GET_ASSET_INFO::request& req, currency::COMMAND_RPC_GET_ASSET_INFO::response& res) { return false; }
virtual bool call_COMMAND_RPC_INVOKE(const std::string& uri, const std::string& body, int& response_code, std::string& response_body) { return false; }
i_core_proxy()
{

View file

@ -201,11 +201,13 @@ public:
std::list<tools::wallet_public::asset_balance_entry> balances;
uint64_t minied_total;
bool has_bare_unspent_outputs;
BEGIN_KV_SERIALIZE_MAP()
KV_CHAIN_BASE(wallet_status_info_base)
KV_SERIALIZE(balances)
KV_SERIALIZE(minied_total)
KV_SERIALIZE(has_bare_unspent_outputs)
END_KV_SERIALIZE_MAP()
};
@ -729,12 +731,14 @@ public:
struct gui_options
{
bool use_debug_mode;
bool disable_price_fetch;
bool use_debug_mode = false;
bool disable_price_fetch = false;
int32_t rpc_port = 0;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(use_debug_mode)
KV_SERIALIZE(disable_price_fetch)
KV_SERIALIZE(rpc_port)
END_KV_SERIALIZE_MAP()
};

View file

@ -352,31 +352,6 @@ const currency::txout_htlc& out_get_htlc(const currency::tx_out_v& out_t)
return boost::get<currency::txout_htlc>(boost::get<currency::tx_out_bare>(out_t).target);
}
uint8_t wallet2::out_get_mixin_attr(const currency::tx_out_v& out_t)
{
if (out_t.type() == typeid(currency::tx_out_bare))
{
if (boost::get<currency::tx_out_bare>(out_t).target.type() == typeid(currency::txout_to_key))
{
return boost::get<currency::txout_to_key>(boost::get<currency::tx_out_bare>(out_t).target).mix_attr;
}
else
{
THROW_WALLET_CMN_ERR_EX("Unexpected type in out_get_mixin_attr");
}
}
else if (out_t.type() == typeid(currency::tx_out_zarcanum))
{
return boost::get<currency::tx_out_zarcanum>(out_t).mix_attr;
}
else
{
THROW_WALLET_CMN_ERR_EX("Unexpected type in out_get_mixin_attr");
}
THROW_WALLET_CMN_ERR_EX("Unexpected out type im wallet: " << out_t.type().name());
return false;
}
const crypto::public_key& wallet2::out_get_pub_key(const currency::tx_out_v& out_t, std::list<currency::htlc_info>& htlc_info_list)
{
if (out_t.type() == typeid(tx_out_bare))
@ -424,16 +399,17 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
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;
epee::misc_utils::cast_assign_a_to_b(asset_context, ado.descriptor);
//*static_cast<asset_descriptor_base*>(&asset_context) = ado.descriptor;
std::stringstream ss;
ss << "New Asset Registered:"
<< ENDL << "asset id: " << asset_id
<< ENDL << "Name: " << asset_context.asset_descriptor.full_name
<< ENDL << "Ticker: " << asset_context.asset_descriptor.ticker
<< ENDL << "Total Max Supply: " << print_asset_money(asset_context.asset_descriptor.total_max_supply, asset_context.asset_descriptor.decimal_point)
<< ENDL << "Current Supply: " << print_asset_money(asset_context.asset_descriptor.current_supply, asset_context.asset_descriptor.decimal_point)
<< ENDL << "Decimal Point: " << (int)asset_context.asset_descriptor.decimal_point;
<< ENDL << "Name: " << asset_context.full_name
<< ENDL << "Ticker: " << asset_context.ticker
<< ENDL << "Total Max Supply: " << print_asset_money(asset_context.total_max_supply, asset_context.decimal_point)
<< ENDL << "Current Supply: " << print_asset_money(asset_context.current_supply, asset_context.decimal_point)
<< ENDL << "Decimal Point: " << (int)asset_context.decimal_point;
add_rollback_event(ptc.height, asset_register_event{ asset_id });
@ -448,7 +424,8 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
break;
//asset had been updated
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
epee::misc_utils::cast_assign_a_to_b(it->second, ado.descriptor);
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE )
{
@ -460,7 +437,7 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
// ownership of the asset acquired
wallet_own_asset_context& asset_context = m_own_asset_descriptors[asset_id];
asset_context.asset_descriptor = ado.descriptor;
epee::misc_utils::cast_assign_a_to_b(asset_context, ado.descriptor);
std::stringstream ss;
ss << "Asset ownership acquired:"
@ -511,7 +488,8 @@ void wallet2::process_ado_in_new_transaction(const currency::asset_descriptor_op
{
//just an update of the asset
add_rollback_event(ptc.height, asset_update_event{ it->first, it->second });
it->second.asset_descriptor = ado.descriptor;
epee::misc_utils::cast_assign_a_to_b(it->second, ado.descriptor);
}
}
}
@ -523,6 +501,64 @@ void wallet2::add_rollback_event(uint64_t h, const wallet_event_t& ev)
m_rollback_events.emplace_back(h, ev);
}
//----------------------------------------------------------------------------------------------------
#define M_LAST_ZC_GLOBAL_INDEXS_MAX_SIZE 30
void wallet2::add_to_last_zc_global_indexs(uint64_t h, uint64_t last_zc_output_index)
{
if (m_last_zc_global_indexs.size())
{
if (h > m_last_zc_global_indexs.begin()->first)
{
//new block added on top of last one, simply add new record
m_last_zc_global_indexs.push_front(std::make_pair(h, last_zc_output_index));
}
else if (h < m_last_zc_global_indexs.begin()->first)
{
//looks like reorganize, pop all records before
while (m_last_zc_global_indexs.size() && m_last_zc_global_indexs.begin()->first >= h)
{
m_last_zc_global_indexs.erase(m_last_zc_global_indexs.begin());
}
m_last_zc_global_indexs.push_front(std::make_pair(h, last_zc_output_index));
}
else
{
//@#@
#ifdef _DEBUG
if (m_last_zc_global_indexs.begin()->second > last_zc_output_index)
{
LOG_ERROR("!!!!!!!!!!!!!!!!!");
}
#endif
//equals, same h but new last_zc_output_index, just update it, should be always bigger then prev
WLT_THROW_IF_FALSE_WITH_CODE(m_last_zc_global_indexs.begin()->second <= last_zc_output_index,
"condition m_last_zc_global_indexs.begin()->second " << m_last_zc_global_indexs.begin()->second << " <= last_zc_output_index " << last_zc_output_index << " failed", API_RETURN_CODE_INTERNAL_ERROR);
m_last_zc_global_indexs.begin()->second = last_zc_output_index;
}
}
else
{
//new block added on top of last one, simply add new record
m_last_zc_global_indexs.push_front(std::make_pair(h, last_zc_output_index));
}
if (m_last_zc_global_indexs.size() > M_LAST_ZC_GLOBAL_INDEXS_MAX_SIZE)
m_last_zc_global_indexs.pop_back();
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_actual_zc_global_index()
{
WLT_THROW_IF_FALSE_WITH_CODE(m_last_zc_global_indexs.size(), "m_last_zc_global_indexs is empty", API_RETURN_CODE_INTERNAL_ERROR);
for (auto it = m_last_zc_global_indexs.begin(); it != m_last_zc_global_indexs.end(); it++)
{
if (it->first <= m_last_known_daemon_height - WALLET_DEFAULT_TX_SPENDABLE_AGE)
{
return it->second;
}
}
WLT_THROW_IF_FALSE_WITH_CODE(false, "doesn't have anything that match expected height = " << m_last_known_daemon_height - WALLET_DEFAULT_TX_SPENDABLE_AGE, API_RETURN_CODE_INTERNAL_ERROR);
throw std::runtime_error(""); //mostly to suppress compiler warning
}
//----------------------------------------------------------------------------------------------------
void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t height, const currency::block& b, const std::vector<uint64_t>* pglobal_indexes)
{
//check for transaction spends
@ -540,11 +576,9 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
{
if (pglobal_indexes->size())
{
//store global index that is under coinage, so we can used in decoy selection algo
if (ptc.height < m_last_known_daemon_height && m_last_known_daemon_height - ptc.height > WALLET_DEFAULT_TX_SPENDABLE_AGE)
{
m_last_zc_global_index = pglobal_indexes->back();
}
//@#@
WLT_LOG_L2("add_to_last_zc_global_indexs: h: " << height << ", b: " << currency::get_block_hash(b) << " , tx: " << currency::get_transaction_hash(tx) << ", last_zc_output_index: " << pglobal_indexes->back());
add_to_last_zc_global_indexs(ptc.height, pglobal_indexes->back());
}
}
@ -742,15 +776,16 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
}
}
if (is_auditable() && (out_type_to_key || out_type_zc) &&
out_get_mixin_attr(out_v) != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
uint8_t mix_attr = CURRENCY_TO_KEY_OUT_RELAXED;
[[maybe_unused]] bool mix_attr_r = get_mix_attr_from_tx_out_v(out_v, mix_attr);
if (is_auditable() && (out_type_to_key || out_type_zc) && mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
{
std::stringstream ss;
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.";
<< " is targeted to this auditable wallet and has INCORRECT mix_attr = " << (uint64_t)mix_attr << ". Output is IGNORED.";
WLT_LOG_YELLOW(ss.str(), LOG_LEVEL_0);
if (m_wcallback)
m_wcallback->on_message(i_wallet2_callback::ms_red, ss.str());
@ -1120,7 +1155,8 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
//---------------------------------------------------------------------------------
uint64_t wallet2::get_current_tx_version()
{
return currency::get_tx_version(this->get_top_block_height(), this->m_core_runtime_config.hard_forks);
uint64_t tx_expected_block_height = get_top_block_height() + 1;
return currency::get_tx_version(tx_expected_block_height, this->m_core_runtime_config.hard_forks);
}
//---------------------------------------------------------------------------------
void wallet2::finish_contract(const crypto::hash& contract_id, const std::string& release_type, currency::transaction* p_release_tx /* = nullptr */)
@ -1857,9 +1893,16 @@ void wallet2::process_new_blockchain_entry(const currency::block& b, const curre
TIME_MEASURE_FINISH(miner_tx_handle_time);
TIME_MEASURE_START(txs_handle_time);
size_t count = 0;
for(const auto& tx_entry: bche.txs_ptr)
{
if (b.tx_hashes.size() < count || currency::get_transaction_hash(tx_entry->tx) != b.tx_hashes[count])
{
LOG_ERROR("Found tx order fail in process_new_blockchain_entry: count=" << count
<< ", b.tx_hashes.size() = " << b.tx_hashes.size() << ", tx real id: " << currency::get_transaction_hash(tx_entry->tx) << ", bl_id: " << bl_id);
}
process_new_transaction(tx_entry->tx, height, b, &(tx_entry->m_global_output_indexes));
count++;
}
TIME_MEASURE_FINISH(txs_handle_time);
WLT_LOG_L3("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms");
@ -2200,6 +2243,190 @@ bool wallet2::has_related_alias_entry_unconfirmed(const currency::transaction& t
return false;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::has_bare_unspent_outputs() const
{
if (m_account.get_createtime() > ZANO_HARDFORK_04_TIMESTAMP_ACTUAL)
return false;
[[maybe_unused]] uint64_t bal = 0;
if (!m_has_bare_unspent_outputs.has_value())
bal = balance();
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(m_has_bare_unspent_outputs.has_value(), "m_has_bare_unspent_outputs has no value after balance()");
return m_has_bare_unspent_outputs.value();
}
//----------------------------------------------------------------------------------------------------
#define MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC 20
bool wallet2::get_bare_unspent_outputs_stats(std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs) const
{
tids_grouped_by_txs.clear();
// 1/3. Populate a list of bare unspent outputs
std::unordered_map<crypto::hash, std::vector<size_t>> buo_ids; // tx hash -> Bare Unspent Outs list
for(size_t tid = 0; tid != m_transfers.size(); ++tid)
{
const auto& td = m_transfers[tid];
if (!td.is_zc() && td.is_spendable())
{
buo_ids[td.tx_hash()].push_back(tid);
}
}
if (buo_ids.empty())
return true;
// 2/3. Split them into groups
tids_grouped_by_txs.emplace_back();
for(auto& buo_el : buo_ids)
{
if (tids_grouped_by_txs.back().tids.size() + buo_el.second.size() > MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC)
tids_grouped_by_txs.emplace_back();
for(auto& tid : buo_el.second)
{
if (tids_grouped_by_txs.back().tids.size() >= MAX_INPUTS_FOR_SIMPLE_TX_EURISTIC)
tids_grouped_by_txs.emplace_back();
tids_grouped_by_txs.back().tids.push_back((uint64_t)tid);
tids_grouped_by_txs.back().total_amount += m_transfers[tid].m_amount;
}
}
// 3/3. Iterate through groups and check whether total amount is big enough to cover min fee.
// Add additional zc output if not.
std::multimap<uint64_t, size_t> usable_zc_outs_tids; // grouped by amount
bool usable_zc_outs_tids_precalculated = false;
auto precalculate_usable_zc_outs_if_needed = [&](){
if (usable_zc_outs_tids_precalculated)
return;
size_t decoys = is_auditable() ? 0 : m_core_runtime_config.hf4_minimum_mixins;
for(size_t tid = 0; tid != m_transfers.size(); ++tid)
{
auto& td = m_transfers[tid];
if (td.is_zc() && td.is_native_coin() && is_transfer_ready_to_go(td, decoys))
usable_zc_outs_tids.insert(std::make_pair(td.m_amount, tid));
}
usable_zc_outs_tids_precalculated = true;
};
std::unordered_set<size_t> used_zc_outs;
for(auto it = tids_grouped_by_txs.begin(); it != tids_grouped_by_txs.end(); )
{
auto& group = *it;
if (group.total_amount < TX_MINIMUM_FEE)
{
precalculate_usable_zc_outs_if_needed();
uint64_t min_required_amount = TX_MINIMUM_FEE - group.total_amount;
auto jt = usable_zc_outs_tids.lower_bound(min_required_amount);
bool found = false;
while(jt != usable_zc_outs_tids.end())
{
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(jt->first >= min_required_amount, "jt->first=" << jt->first << ", min_required_amount=" << min_required_amount);
if (used_zc_outs.count(jt->second) == 0)
{
group.tids.push_back((uint64_t)jt->second);
used_zc_outs.insert(jt->second);
group.additional_tid = true;
group.additional_tid_amount = jt->first;
found = true;
break;
}
++jt;
}
if (!found)
{
// no usable outs for required amount, remove this group and go to the next
it = tids_grouped_by_txs.erase(it);
continue;
}
}
++it;
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
std::function<void(size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err)> on_tx_sent)
{
if (m_watch_only)
return false;
size_t decoys_count = is_auditable() ? 0 : CURRENCY_DEFAULT_DECOY_SET_SIZE;
bool send_to_network = true;
size_t batch_index = 0;
for(const batch_of_bare_unspent_outs& group : tids_grouped_by_txs)
{
currency::finalized_tx ftx{};
currency::finalize_tx_param ftp{};
ftp.pevents_dispatcher = &m_debug_events_dispatcher;
ftp.tx_version = this->get_current_tx_version();
if (!prepare_tx_sources(decoys_count, /*use_all_decoys_if_found_less_than_required*/ true, ftp.sources, group.tids))
{
on_tx_sent(batch_index, transaction{}, 0, 0, false, "sources for tx couldn't be prepared");
LOG_PRINT_L0("prepare_tx_sources failed, batch_index = " << batch_index);
return false;
}
uint64_t fee = TX_DEFAULT_FEE;
std::vector<tx_destination_entry> destinations{tx_destination_entry(group.total_amount + group.additional_tid_amount - fee, target_address)};
assets_selection_context needed_money_map{std::make_pair(native_coin_asset_id, selection_for_amount{group.total_amount + group.additional_tid_amount, group.total_amount + group.additional_tid_amount})};
try
{
prepare_tx_destinations(needed_money_map, get_current_split_strategy(), tx_dust_policy{}, destinations, 0 /* tx_flags */, ftp.prepared_destinations);
}
catch(...)
{
on_tx_sent(batch_index, transaction{}, 0, 0, false, "destinations for tx couldn't be prepared");
LOG_PRINT_L0("prepare_tx_destinations failed, batch_index = " << batch_index);
return false;
}
mark_transfers_as_spent(ftp.selected_transfers, std::string("sweep bare UTXO, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(ftx.tx)));
try
{
finalize_transaction(ftp, ftx, send_to_network);
on_tx_sent(batch_index, ftx.tx, group.total_amount + group.additional_tid_amount, fee, true, std::string());
}
catch(std::exception& e)
{
clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception on sweep bare UTXO, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(ftx.tx)));
on_tx_sent(batch_index, transaction{}, 0, 0, false, e.what());
return false;
}
++batch_index;
}
return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
size_t& total_txs_sent, uint64_t& total_amount_sent, uint64_t& total_fee_spent, uint64_t& total_bare_outs_sent)
{
total_txs_sent = 0;
total_amount_sent = 0;
total_fee_spent = 0;
total_bare_outs_sent = 0;
auto on_tx_sent_callback = [&](size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err) {
if (sent_ok)
{
total_bare_outs_sent += count_type_in_variant_container<txin_to_key>(tx.vin);
++total_txs_sent;
total_fee_spent += fee;
total_amount_sent += amount;
}
};
return sweep_bare_unspent_outputs(target_address, tids_grouped_by_txs, on_tx_sent_callback);
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_directly_spent_transfer_index_by_input_in_tracking_wallet(const currency::txin_to_key& intk)
{
return get_directly_spent_transfer_index_by_input_in_tracking_wallet(intk.amount, intk.key_offsets);
@ -2861,6 +3088,12 @@ void wallet2::detach_blockchain(uint64_t including_height)
++it;
}
//detach in m_last_zc_global_indexs
while (m_last_zc_global_indexs.size() && including_height <= m_last_zc_global_indexs.begin()->first )
{
m_last_zc_global_indexs.erase(m_last_zc_global_indexs.begin());
}
//asset descriptors
handle_rollback_events(including_height);
@ -3444,6 +3677,7 @@ uint64_t wallet2::balance(const crypto::public_key& asset_id) const
bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base>& balances, uint64_t& mined) const
{
mined = 0;
m_has_bare_unspent_outputs = false;
for(auto& td : m_transfers)
{
@ -3464,6 +3698,9 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
mined += CURRENCY_BLOCK_REWARD; //this code would work only for cases where block reward is full. For reduced block rewards might need more flexible code (TODO)
}
}
if (!td.is_zc())
m_has_bare_unspent_outputs = true;
}
}
@ -3519,7 +3756,7 @@ bool wallet2::balance(std::list<wallet_public::asset_balance_entry>& balances, u
{
if (m_whitelisted_assets.find(own_asset.first) == m_whitelisted_assets.end())
{
custom_assets_local[own_asset.first] = own_asset.second.asset_descriptor;
custom_assets_local[own_asset.first] = own_asset.second;
}
}
@ -3634,7 +3871,7 @@ bool wallet2::add_custom_asset_id(const crypto::public_key& asset_id, asset_desc
//----------------------------------------------------------------------------------------------------
bool wallet2::delete_custom_asset_id(const crypto::public_key& asset_id)
{
auto it = m_custom_assets.find(asset_id);
const auto it = m_custom_assets.find(asset_id);
if (it != m_custom_assets.end())
{
m_custom_assets.erase(it);
@ -3643,6 +3880,21 @@ bool wallet2::delete_custom_asset_id(const crypto::public_key& asset_id)
return true;
}
//----------------------------------------------------------------------------------------------------
const std::unordered_map<crypto::public_key, currency::asset_descriptor_base>& wallet2::get_local_whitelist() const
{
return m_custom_assets;
}
//----------------------------------------------------------------------------------------------------
const std::unordered_map<crypto::public_key, currency::asset_descriptor_base>& wallet2::get_global_whitelist() const
{
return m_whitelisted_assets;
}
//----------------------------------------------------------------------------------------------------
const std::unordered_map<crypto::public_key, tools::wallet_own_asset_context>& wallet2::get_own_assets() const
{
return m_own_asset_descriptors;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::load_whitelisted_tokens() const
{
if(!m_use_assets_whitelisting)
@ -3656,9 +3908,10 @@ bool wallet2::load_whitelisted_tokens() const
for (auto it = aw.assets.begin(); it != aw.assets.end(); it++)
{
m_whitelisted_assets[it->asset_id] = static_cast<currency::asset_descriptor_base>(*it);
}
}
return true;
}
return true;
return false;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::load_whitelisted_tokens_if_not_loaded() const
@ -3778,6 +4031,59 @@ std::string wallet2::get_balance_str() const
return ss.str();
}
//----------------------------------------------------------------------------------------------------
std::string wallet2::get_balance_str_raw() const
{
// balance unlocked / [balance total] ticker asset id
// 1391306.970000000000 / 1391306.970000000000 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 1391306.97 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
// 106.971 / 206.4 ZANO d6329b5b1f7c0805b5c345f4957554002a2f557845f64d7645dae0e051a6498a
static const char* header = " balance unlocked / [balance total] asset id";
std::stringstream ss;
ss << header << ENDL;
uint64_t dummy = 0;
std::unordered_map<crypto::public_key, wallet_public::asset_balance_entry_base> balances_map;
this->balance(balances_map, dummy);
for(const auto& entry : balances_map)
{
ss << " " << std::left << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(entry.second.unlocked, 12);
if(entry.second.total == entry.second.unlocked)
ss << " ";
else
ss << " / " << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(entry.second.total, 12);
ss << " " << std::setw(8) << std::left << entry.first << ENDL;
}
//print whitelist
ss << "WHITELIST: " << ENDL;
for(const auto& entry : m_whitelisted_assets)
{
ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL;
}
// print whitelist
ss << "CUSTOM LIST: " << ENDL;
for(const auto& entry : m_custom_assets)
{
ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL;
}
ss << "OWN DESCRIPTORS LIST: " << ENDL;
for(const auto& entry : m_own_asset_descriptors)
{
ss << " " << std::left << entry.first << " " << entry.second.ticker << ENDL;
}
return ss.str();
}
//----------------------------------------------------------------------------------------------------
void wallet2::get_payments(const std::string& payment_id, std::list<payment_details>& payments, uint64_t min_height) const
{
auto range = m_payments.equal_range(payment_id);
@ -4249,6 +4555,11 @@ bool wallet2::is_in_hardfork_zone(uint64_t hardfork_index) const
return m_core_runtime_config.is_hardfork_active_for_height(hardfork_index, get_blockchain_current_size());
}
//----------------------------------------------------------------------------------------------------
bool wallet2::proxy_to_daemon(const std::string& uri, const std::string& body, int& response_code, std::string& response_body)
{
return m_core_proxy->call_COMMAND_RPC_INVOKE(uri, body, response_code, response_body);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t full_block_reward, const currency::pos_entry& pe, currency::tx_generation_context& miner_tx_tgc, currency::block& b) const
{
bool r = false;
@ -4291,7 +4602,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful
if (m_required_decoys_count > 0 && !is_auditable())
{
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request decoys_req = AUTO_VAL_INIT(decoys_req);
decoys_req.height_upper_limit = 0; // TODO @#@# maybe use m_last_pow_block_h like Zarcanum?
decoys_req.height_upper_limit = std::min(m_last_pow_block_h, m_last_known_daemon_height > m_core_runtime_config.min_coinstake_age ? m_last_known_daemon_height - m_core_runtime_config.min_coinstake_age : m_last_pow_block_h);
decoys_req.use_forced_mix_outs = false;
decoys_req.decoys_count = m_required_decoys_count + 1; // one more to be able to skip a decoy in case it hits the real output
decoys_req.amounts.push_back(pe.amount); // request one batch of decoys
@ -4576,15 +4887,16 @@ bool wallet2::try_mint_pos(const currency::account_public_address& miner_address
return true;
}, m_core_runtime_config);
bool res = true;
if (ctx.status == API_RETURN_CODE_OK)
{
build_minted_block(ctx, miner_address);
res = build_minted_block(ctx, miner_address);
}
TIME_MEASURE_FINISH_MS(mining_duration_ms);
WLT_LOG_L0("PoS mining: " << ctx.iterations_processed << " iterations finished (" << std::fixed << std::setprecision(2) << (mining_duration_ms / 1000.0f) << "s), status: " << ctx.status << ", " << ctx.total_items_checked << " entries with total amount: " << print_money_brief(ctx.total_amount_checked));
return true;
return res;
}
//------------------------------------------------------------------
void wallet2::do_pos_mining_prepare_entry(mining_context& context, size_t transfer_index)
@ -5644,7 +5956,7 @@ bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal
construct_tx_param ctp = get_default_construct_tx_param();
ctp.fake_outputs_count = proposal_detais.mixins;
//ctp.fake_outputs_count = proposal_detais.mixins;
ctp.fee = proposal_detais.fee_paid_by_a;
ctp.flags = TX_FLAG_SIGNATURE_MODE_SEPARATE;
ctp.mark_tx_as_complete = false;
@ -5789,10 +6101,10 @@ bool wallet2::get_ionic_swap_proposal_info(const wallet_public::ionic_swap_propo
}
amounts_provided_by_a[in_asset_id] += amount;
if (proposal_info.mixins == 0 || proposal_info.mixins > mx)
{
proposal_info.mixins = mx;
}
//if (proposal_info.mixins == 0 || proposal_info.mixins > mx)
//{
// proposal_info.mixins = mx;
//}
}
@ -5991,10 +6303,18 @@ bool wallet2::prepare_tx_sources_for_defragmentation_tx(std::vector<currency::tx
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies)
{
bool r = select_transfers(needed_money_map, fake_outputs_count, dust_threshold, selected_indicies);
if (!r)
return r;
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies);
try
{
select_transfers(needed_money_map, fake_outputs_count, dust_threshold, selected_indicies); // always returns true, TODO consider refactoring -- sowle
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies);
}
catch(...)
{
// if smth went wrong -- invalidate transfers cache to trigger its regeneration on the next use
// it is necessary because it may be in invalid state (some items might be erased within select_indices_for_transfer() or expand_selection_with_zc_input())
m_found_free_amounts.clear();
throw;
}
}
//----------------------------------------------------------------------------------------------------
void wallet2::prefetch_global_indicies_if_needed(const std::vector<uint64_t>& selected_indicies)
@ -6024,7 +6344,12 @@ void wallet2::prefetch_global_indicies_if_needed(const std::vector<uint64_t>& se
}*/
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies)
bool wallet2::prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies)
{
return prepare_tx_sources(fake_outputs_count, false, sources, selected_indicies);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, bool use_all_decoys_if_found_less_than_required, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies)
{
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
typedef currency::tx_source_entry::output_entry tx_output_entry;
@ -6037,13 +6362,6 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector<currenc
size_t fake_outputs_count = fake_outputs_count_;
uint64_t zarcanum_start_from = m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM];
uint64_t current_size = m_chain.get_blockchain_current_size();
decoy_selection_generator zarcanum_decoy_set_generator;
if (current_size - 1 >= zarcanum_start_from)
{
//in Zarcanum era
//const uint64_t test_scale_size = current_size - 1 - zarcanum_start_from;
zarcanum_decoy_set_generator.init(m_last_zc_global_index);
}
bool need_to_request = fake_outputs_count != 0;
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS3::request req = AUTO_VAL_INIT(req);
@ -6069,7 +6387,7 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector<currenc
//Zarcanum era
rdisttib.amount = 0;
//generate distribution in Zarcanum hardfork
build_distribution_for_input(zarcanum_decoy_set_generator, rdisttib.global_offsets, it->m_global_output_index);
build_distribution_for_input(rdisttib.global_offsets, it->m_global_output_index);
need_to_request = true;
}
else
@ -6109,14 +6427,15 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector<currenc
std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs;
THROW_IF_FALSE_WALLET_EX(daemon_resp.outs.size() == req.amounts.size(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
for(size_t i = 0; i != daemon_resp.outs.size(); i++)
if (!use_all_decoys_if_found_less_than_required)
{
if (req.amounts[i].amount != 0 && daemon_resp.outs[i].outs.size() != req.amounts[i].global_offsets.size())
{
scanty_outs.push_back(daemon_resp.outs[i]);
}
// make sure we have received the requested number of decoys
for(size_t i = 0; i != daemon_resp.outs.size(); i++)
if (req.amounts[i].amount != 0 && daemon_resp.outs[i].outs.size() != req.amounts[i].global_offsets.size())
scanty_outs.push_back(daemon_resp.outs[i]);
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
}
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
}
}
@ -6287,12 +6606,16 @@ void wallet2::select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS
amount_entry.outs = local_outs;
}
//----------------------------------------------------------------------------------------------------------------
void wallet2::build_distribution_for_input(decoy_selection_generator& zarcanum_decoy_set_generator, std::vector<uint64_t>& offsets, uint64_t own_index)
void wallet2::build_distribution_for_input(std::vector<uint64_t>& offsets, uint64_t own_index)
{
decoy_selection_generator zarcanum_decoy_set_generator;
zarcanum_decoy_set_generator.init(get_actual_zc_global_index());
THROW_IF_FALSE_WALLET_INT_ERR_EX(zarcanum_decoy_set_generator.is_initialized(), "zarcanum_decoy_set_generator are not initialized");
if (m_core_runtime_config.hf4_minimum_mixins)
{
offsets = zarcanum_decoy_set_generator.generate_unique_reversed_distribution(m_last_zc_global_index - 1 > WALLET_FETCH_RANDOM_OUTS_SIZE ? WALLET_FETCH_RANDOM_OUTS_SIZE: m_last_zc_global_index - 1, own_index);
uint64_t actual_zc_index = get_actual_zc_global_index();
offsets = zarcanum_decoy_set_generator.generate_unique_reversed_distribution(actual_zc_index - 1 > WALLET_FETCH_RANDOM_OUTS_SIZE ? WALLET_FETCH_RANDOM_OUTS_SIZE : actual_zc_index - 1, own_index);
}
}
//----------------------------------------------------------------------------------------------------------------
@ -6709,8 +7032,6 @@ bool wallet2::expand_selection_with_zc_input(assets_selection_context& needed_mo
//----------------------------------------------------------------------------------------------------
bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes)
{
bool res = true;
//
for (auto& item : needed_money_map)
{
if(item.second.needed_amount == 0)
@ -6737,8 +7058,7 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money
}
}
return res;
return true;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_indexes, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count_)
@ -6777,7 +7097,7 @@ uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_in
return found_money;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count)
bool wallet2::is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count) const
{
if (is_transfer_able_to_go(td, fake_outputs_count) && is_transfer_unlocked(td))
{
@ -6786,7 +7106,7 @@ bool wallet2::is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_
return false;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count)
bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count) const
{
if (!td.is_spendable())
return false;
@ -6854,7 +7174,7 @@ void wallet2::add_transfer_to_transfers_cache(uint64_t amount, uint64_t index, c
m_found_free_amounts[asset_id][amount].insert(index);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::select_transfers(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust, std::vector<uint64_t>& selected_indicies)
bool wallet2::select_transfers(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t /*dust_threshold*/, std::vector<uint64_t>& selected_indicies)
{
prepare_free_transfers_cache(fake_outputs_count);
return select_indices_for_transfer(needed_money_map, fake_outputs_count, selected_indicies);
@ -7092,7 +7412,7 @@ void wallet2::prepare_tx_destinations(uint64_t needed_money,
const crypto::public_key& asset_id,
std::vector<currency::tx_destination_entry>& final_destinations)
{
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(found_money >= needed_money, "needed_money==" << needed_money << " < found_money==" << found_money);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(found_money >= needed_money, "found_money = " << print_money_brief(found_money) << " is less than needed_money = " << print_money_brief(needed_money) << ", assed_id: " << asset_id);
if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))
{
@ -7244,10 +7564,6 @@ void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::f
// broadcasting tx without secret key storing is forbidden to avoid lost key issues
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!broadcast_tx || store_tx_secret_key, "finalize_tx is requested to broadcast a tx without storing the key");
//overide mixins count for hardfork 4 outputs
if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))
ftp.tx_outs_attr = m_core_runtime_config.hf4_minimum_mixins;
bool r = currency::construct_tx(m_account.get_keys(),
ftp, result);
//TIME_MEASURE_FINISH_MS(construct_tx_time);

View file

@ -148,9 +148,7 @@ namespace tools
std::unordered_map<crypto::public_key, crypto::key_image> m_pending_key_images; // (out_pk -> ki) pairs of change outputs to be added in watch-only wallet without spend sec key
uint64_t m_last_pow_block_h = 0;
std::list<std::pair<uint64_t, wallet_event_t>> m_rollback_events;
uint64_t m_last_zc_global_index = 0;
std::list<std::pair<uint64_t, uint64_t> > m_last_zc_global_indexs; // <height, last_zc_global_indexs>, biggest height comes in front
//variables that not being serialized
std::atomic<uint64_t> m_last_bc_timestamp = 0;
@ -158,8 +156,10 @@ namespace tools
std::atomic<uint64_t> m_last_sync_percent = 0;
mutable uint64_t m_current_wallet_file_size = 0;
bool m_use_assets_whitelisting = true;
mutable std::optional<bool> m_has_bare_unspent_outputs; // recalculated each time the balance() is called
// variables that should be part of state data object but should not be stored during serialization
mutable std::atomic<bool> m_whitelist_updated = false;
//===============================================================
template <class t_archive>
inline void serialize(t_archive &a, const unsigned int ver)
@ -222,7 +222,19 @@ namespace tools
a & m_rollback_events;
a & m_whitelisted_assets;
a & m_use_assets_whitelisting;
a & m_last_zc_global_index;
if (ver <= 165)
{
uint64_t last_zc_global_index = 0;
a& last_zc_global_index;
m_last_zc_global_indexs.push_back(std::make_pair(uint64_t(0), last_zc_global_index));
return;
}
a& m_last_zc_global_indexs;
if (ver == 166 && m_last_zc_global_indexs.size())
{
//workaround for m_last_zc_global_indexs holding invalid index for last item
m_last_zc_global_indexs.pop_front();
}
}
};
@ -232,6 +244,7 @@ namespace tools
wallet2(const wallet2&) = delete;
public:
wallet2();
virtual ~wallet2() {}
static std::string transfer_flags_to_str(uint32_t flags);
@ -342,6 +355,13 @@ namespace tools
mutable crypto::hash tx_hash_ = currency::null_hash;
};
struct batch_of_bare_unspent_outs
{
std::vector<uint64_t> tids;
uint64_t total_amount = 0;
bool additional_tid = false; // additional zc transfer if total_amount < min fee
uint64_t additional_tid_amount = 0;
};
@ -377,6 +397,12 @@ namespace tools
void set_do_rise_transfer(bool do_rise) { m_do_rise_transfer = do_rise; }
bool has_related_alias_entry_unconfirmed(const currency::transaction& tx);
bool has_bare_unspent_outputs() const;
bool get_bare_unspent_outputs_stats(std::vector<batch_of_bare_unspent_outs>& buo_txs) const;
bool sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
std::function<void(size_t batch_index, const currency::transaction& tx, uint64_t amount, uint64_t fee, bool sent_ok, const std::string& err)> on_tx_sent);
bool sweep_bare_unspent_outputs(const currency::account_public_address& target_address, const std::vector<batch_of_bare_unspent_outs>& tids_grouped_by_txs,
size_t& total_txs_sent, uint64_t& total_amount_sent, uint64_t& total_fee, uint64_t& total_bare_outs_sent);
void handle_unconfirmed_tx(process_transaction_context& ptc);
void scan_tx_pool(bool& has_related_alias_in_unconfirmed);
void refresh();
@ -400,7 +426,6 @@ namespace tools
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_defragmentation_tx_settings(bool enabled, uint64_t min_outs, uint64_t max_outs, uint64_t max_allowed_amount = CURRENCY_BLOCK_REWARD, size_t decoys_count = SIZE_MAX);
void set_pos_required_decoys_count(size_t v) { m_required_decoys_count = v; }
@ -540,6 +565,7 @@ namespace tools
void get_transfers(transfer_container& incoming_transfers) const;
std::string get_transfers_str(bool include_spent = true, bool include_unspent = true, bool show_only_unknown = false, const std::string& filter_asset_ticker = std::string{}) const;
std::string get_balance_str() const;
std::string get_balance_str_raw() const;
// Returns all payments by given id in unspecified order
void get_payments(const std::string& payment_id, std::list<payment_details>& payments, uint64_t min_height = 0) const;
@ -576,8 +602,8 @@ namespace tools
wallet2_base_state::serialize(a, ver);
}
bool is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count);
bool is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count);
bool is_transfer_ready_to_go(const transfer_details& td, uint64_t fake_outputs_count) const;
bool is_transfer_able_to_go(const transfer_details& td, uint64_t fake_outputs_count) const;
uint64_t select_indices_for_transfer(std::vector<uint64_t>& ind, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count);
bool select_indices_for_transfer(assets_selection_context& needed_money_map, uint64_t fake_outputs_count, std::vector<uint64_t>& selected_indexes);
@ -660,6 +686,10 @@ namespace tools
bool add_custom_asset_id(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_descriptor);
bool delete_custom_asset_id(const crypto::public_key& asset_id);
const std::unordered_map<crypto::public_key, currency::asset_descriptor_base>& get_local_whitelist() const;
const std::unordered_map<crypto::public_key, currency::asset_descriptor_base>& get_global_whitelist() const;
const std::unordered_map<crypto::public_key, tools::wallet_own_asset_context>& get_own_assets() const;
bool load_whitelisted_tokens_if_not_loaded() const;
bool load_whitelisted_tokens() const;
@ -696,6 +726,8 @@ namespace tools
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;
//performance inefficient call, suitable only for rare ocasions or super lazy developers
bool proxy_to_daemon(const std::string& uri, const std::string& body, int& response_code, std::string& response_body);
construct_tx_param get_default_construct_tx_param();
@ -748,7 +780,8 @@ private:
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 add_to_last_zc_global_indexs(uint64_t h, uint64_t last_zc_output_index);
uint64_t get_actual_zc_global_index();
void handle_pulled_blocks(size_t& blocks_added, std::atomic<bool>& stop,
currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response& blocks);
std::string get_alias_for_address(const std::string& addr);
@ -762,6 +795,7 @@ private:
bool build_escrow_proposal(bc_services::contract_private_details& ecrow_details, uint64_t fee, uint64_t unlock_time, currency::tx_service_attachment& att, std::vector<uint64_t>& selected_indicies);
bool prepare_tx_sources(assets_selection_context& needed_money_map, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies);
bool prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies);
bool prepare_tx_sources(size_t fake_outputs_count, bool use_all_decoys_if_found_less_than_required, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies);
bool prepare_tx_sources(crypto::hash multisig_id, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
bool prepare_tx_sources_htlc(crypto::hash htlc_tx_id, const std::string& origin, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
bool prepare_tx_sources_for_defragmentation_tx(std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
@ -854,7 +888,7 @@ private:
void remove_transfer_from_amount_gindex_map(uint64_t tid);
uint64_t get_alias_cost(const std::string& alias);
detail::split_strategy_id_t get_current_split_strategy();
void build_distribution_for_input(decoy_selection_generator& zarcanum_decoy_set_generator, std::vector<uint64_t>& offsets, uint64_t own_index);
void build_distribution_for_input(std::vector<uint64_t>& offsets, uint64_t own_index);
void select_decoys(currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount & amount_entry, uint64_t own_g_index);
static void wti_to_csv_entry(std::ostream& ss, const wallet_public::wallet_transfer_info& wti, size_t index);
@ -895,7 +929,6 @@ private:
uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
std::atomic<bool> m_stop;
mutable std::atomic<bool> m_whitelist_updated = false;
std::shared_ptr<i_core_proxy> m_core_proxy;
std::shared_ptr<i_wallet2_callback> m_wcallback;
@ -1076,7 +1109,6 @@ namespace tools
ts_middle -= ts_middle % POS_SCAN_STEP;
uint64_t ts_window = std::min(ts_middle - ts_from, ts_to - ts_middle);
size_t pos_entry_index = 0;
for (size_t transfer_index = 0; transfer_index != m_transfers.size(); transfer_index++)
{
auto& tr = m_transfers[transfer_index];
@ -1144,7 +1176,6 @@ namespace tools
next_turn();
}
++pos_entry_index;
}
cxt.status = API_RETURN_CODE_NOT_FOUND;
return false;

View file

@ -251,19 +251,18 @@ namespace tools
crypto::public_key asset_id = currency::null_pkey;
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(asset_id)
END_BOOST_SERIALIZATION()
END_BOOST_SERIALIZATION()
};
struct wallet_own_asset_context
struct wallet_own_asset_context: public currency::asset_descriptor_base
{
currency::asset_descriptor_base asset_descriptor;
bool thirdparty_custody = false;
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(asset_descriptor)
BOOST_SERIALIZE_BASE_CLASS(currency::asset_descriptor_base)
BOOST_SERIALIZE(thirdparty_custody)
END_BOOST_SERIALIZATION()
END_BOOST_SERIALIZATION()
};
struct asset_update_event

View file

@ -20,6 +20,7 @@ namespace tools
wi.path = epee::string_encoding::wstring_to_utf8(w.get_wallet_path());
wi.is_auditable = w.is_auditable();
wi.is_watch_only = w.is_watch_only();
wi.has_bare_unspent_outputs = w.has_bare_unspent_outputs();
return true;
}
@ -37,21 +38,40 @@ namespace tools
result.hash_sum_matched = false;
result.syntax_correct = acc.restore_from_tracking_seed(seed_phrase);
if (result.syntax_correct)
{
result.tracking = true;
result.address = acc.get_public_address_str();
}
}
else
{
result.syntax_correct = currency::account_base::is_seed_password_protected(seed_phrase, result.require_password);
if (result.syntax_correct && result.require_password)
if (result.syntax_correct )
{
if (seed_password.size())
if (result.require_password)
{
currency::account_base acc;
result.hash_sum_matched = acc.restore_from_seed_phrase(seed_phrase, seed_password);
if (seed_password.size())
{
currency::account_base acc;
result.hash_sum_matched = acc.restore_from_seed_phrase(seed_phrase, seed_password);
if (result.hash_sum_matched)
{
result.address = acc.get_public_address_str();
}
}
else
{
result.hash_sum_matched = false;
}
}
else
{
result.hash_sum_matched = false;
currency::account_base acc;
result.syntax_correct = acc.restore_from_seed_phrase(seed_phrase, "");
if (result.syntax_correct)
{
result.address = acc.get_public_address_str();
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,19 @@ using namespace epee;
#include "wallet_rpc_server_error_codes.h"
#include "wallet_helpers.h"
#include "wrap_service.h"
PUSH_VS_WARNINGS
DISABLE_VS_WARNINGS(4244)
#include "jwt-cpp/jwt.h"
POP_VS_WARNINGS
#include "crypto/bitcoin/sha256_helper.h"
#define JWT_TOKEN_EXPIRATION_MAXIMUM (60 * 60)
#define JWT_TOKEN_CLAIM_NAME_BODY_HASH "body_hash"
#define JWT_TOKEN_CLAIM_NAME_SALT "salt"
#define JWT_TOKEN_CLAIM_NAME_EXPIRATION "exp"
#define JWT_TOKEN_OVERWHELM_LIMIT 100000 // if there are more records in m_jwt_used_salts then we consider it as an attack
#define GET_WALLET() wallet_rpc_locker w(m_pwallet_provider);
@ -37,7 +50,7 @@ using namespace epee;
catch (const tools::error::wallet_error& e) \
{ \
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; \
er.message = std::string("WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR") + e.error_code(); \
er.message = e.error_code(); \
return false; \
} \
catch (const std::exception& e) \
@ -53,6 +66,10 @@ using namespace epee;
return false; \
}
void exception_handler()
{}
namespace tools
{
//-----------------------------------------------------------------------------------
@ -60,6 +77,7 @@ namespace tools
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip ("rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1");
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_miner_text_info ( "miner-text-info", "Wallet password");
const command_line::arg_descriptor<bool> wallet_rpc_server::arg_deaf_mode ( "deaf", "Put wallet into 'deaf' mode make it ignore any rpc commands(usable for safe PoS mining)");
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_jwt_secret("jwt-secret", "Enables JWT auth over secret string provided");
void wallet_rpc_server::init_options(boost::program_options::options_description& desc)
{
@ -67,6 +85,7 @@ namespace tools
command_line::add_arg(desc, arg_rpc_bind_port);
command_line::add_arg(desc, arg_miner_text_info);
command_line::add_arg(desc, arg_deaf_mode);
command_line::add_arg(desc, arg_jwt_secret);
}
//------------------------------------------------------------------------------------------------------------------------------
wallet_rpc_server::wallet_rpc_server(std::shared_ptr<wallet2> wptr):
@ -184,11 +203,81 @@ namespace tools
m_net_server.set_threads_prefix("RPC");
bool r = handle_command_line(vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server");
if(command_line::has_arg(vm, arg_jwt_secret))
{
m_jwt_secret = command_line::get_arg(vm, arg_jwt_secret);
}
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(m_port, m_bind_ip);
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::auth_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context)
{
auto it = std::find_if(query_info.m_header_info.m_etc_fields.begin(), query_info.m_header_info.m_etc_fields.end(), [](const auto& element)
{ return element.first == ZANO_ACCESS_TOKEN; });
if(it == query_info.m_header_info.m_etc_fields.end())
return false;
try
{
if(m_jwt_used_salts.get_set().size() > JWT_TOKEN_OVERWHELM_LIMIT)
{
throw std::runtime_error("Salt is overwhelmed");
}
auto decoded = jwt::decode(it->second, [](const std::string& str)
{ return jwt::base::decode<jwt::alphabet::base64>(jwt::base::pad<jwt::alphabet::base64>(str)); });
auto verifier = jwt::verify().allow_algorithm(jwt::algorithm::hs256 { m_jwt_secret });
verifier.verify(decoded);
std::string body_hash = decoded.get_payload_claim(JWT_TOKEN_CLAIM_NAME_BODY_HASH).as_string();
std::string salt = decoded.get_payload_claim(JWT_TOKEN_CLAIM_NAME_SALT).as_string();
crypto::hash jwt_claim_sha256 = currency::null_hash;
epee::string_tools::hex_to_pod(body_hash, jwt_claim_sha256);
crypto::hash sha256 = crypto::sha256_hash(query_info.m_body.data(), query_info.m_body.size());
if (sha256 != jwt_claim_sha256)
{
throw std::runtime_error("Body hash missmatch");
}
if(m_jwt_used_salts.get_set().find(salt) != m_jwt_used_salts.get_set().end())
{
throw std::runtime_error("Salt reused");
}
uint64_t ticks_now = epee::misc_utils::get_tick_count();
m_jwt_used_salts.add(salt, ticks_now + JWT_TOKEN_EXPIRATION_MAXIMUM);
m_jwt_used_salts.remove_if_expiration_less_than(ticks_now);
LOG_PRINT_L0("JWT token OK");
return true;
}
catch(const std::exception& e)
{
LOG_ERROR("Invalid JWT token: " << e.what());
return false;
}
return false;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context)
{
if (m_jwt_secret.size() && m_conn_context.m_connection_id != RPC_INTERNAL_UI_CONTEXT)
{
if (!auth_http_request(query_info, response, m_conn_context))
{
response.m_response_code = 401;
response.m_response_comment = "Unauthorized";
return true;
}
}
response.m_response_code = 200;
response.m_response_comment = "Ok";
std::string reference_stub;
@ -199,7 +288,7 @@ namespace tools
response.m_response_comment = "Internal Server Error";
return true;
}
if (!handle_http_request_map(query_info, response, m_conn_context, call_found, reference_stub) && response.m_response_code == 200)
if (!handle_http_request_map(query_info, response, m_conn_context, call_found) && response.m_response_code == 200)
{
response.m_response_code = 500;
response.m_response_comment = "Internal Server Error";
@ -214,6 +303,16 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::set_jwt_secret(const std::string& jwt)
{
m_jwt_secret = jwt;
}
//------------------------------------------------------------------------------------------------------------------------------
const std::string& wallet_rpc_server::get_jwt_secret()
{
return m_jwt_secret;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getbalance(const wallet_public::COMMAND_RPC_GET_BALANCE::request& req, wallet_public::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -256,6 +355,7 @@ namespace tools
res.utxo_distribution.push_back(currency::print_money_brief(ent.first) + ":" + std::to_string(ent.second));
res.current_height = w.get_wallet()->get_top_block_height();
res.has_bare_unspent_outputs = w.get_wallet()->has_bare_unspent_outputs();
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
@ -325,7 +425,7 @@ namespace tools
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -357,6 +457,7 @@ namespace tools
}
bool wrap = false;
std::vector<currency::tx_destination_entry>& dsts = ctp.dsts;
for (auto it = req.destinations.begin(); it != req.destinations.end(); it++)
{
currency::tx_destination_entry de;
@ -657,6 +758,78 @@ namespace tools
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_bare_outs_stats(const wallet_public::COMMAND_RPC_GET_BARE_OUTS_STATS ::request& req, wallet_public::COMMAND_RPC_GET_BARE_OUTS_STATS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
if (w.get_wallet()->is_watch_only())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "operation cannot be performed in watch-only wallet";
return false;
}
std::vector<tools::wallet2::batch_of_bare_unspent_outs> groups;
if (!w.get_wallet()->get_bare_unspent_outputs_stats(groups))
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "get_bare_unspent_outputs_stats failed";
return false;
}
res.total_amount = 0;
res.total_bare_outs = 0;
res.expected_total_fee = 0;
res.txs_count = 0;
for(auto &g : groups)
{
for (auto& tid: g.tids)
{
tools::transfer_details td{};
CHECK_AND_ASSERT_THROW_MES(w.get_wallet()->get_transfer_info_by_index(tid, td), "get_transfer_info_by_index failed with index " << tid);
res.total_amount += td.m_amount;
}
++res.txs_count;
res.total_bare_outs += g.tids.size();
res.expected_total_fee += TX_DEFAULT_FEE;
}
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_sweep_bare_outs(const wallet_public::COMMAND_RPC_SWEEP_BARE_OUTS::request& req, wallet_public::COMMAND_RPC_SWEEP_BARE_OUTS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
if (w.get_wallet()->is_watch_only())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "operation cannot be performed in watch-only wallet";
return false;
}
std::vector<tools::wallet2::batch_of_bare_unspent_outs> groups;
if (!w.get_wallet()->get_bare_unspent_outputs_stats(groups))
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "get_bare_unspent_outputs_stats failed";
return false;
}
res.amount_swept = 0;
res.bare_outs_swept = 0;
res.fee_spent = 0;
size_t txs_sent = 0;
w.get_wallet()->sweep_bare_unspent_outputs(w.get_wallet()->get_account().get_public_address(), groups, txs_sent, res.amount_swept, res.fee_spent, res.bare_outs_swept);
res.txs_sent = txs_sent;
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::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)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -1018,6 +1191,106 @@ namespace tools
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_assets_whitelist_get(const wallet_public::COMMAND_ASSETS_WHITELIST_GET::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_GET::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::assets_map_to_assets_list(res.local_whitelist, w.get_wallet()->get_local_whitelist());
currency::assets_map_to_assets_list(res.global_whitelist, w.get_wallet()->get_global_whitelist());
currency::assets_map_to_assets_list(res.own_assets, w.get_wallet()->get_own_assets());
const auto global_whitelist = w.get_wallet()->get_global_whitelist();
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_assets_whitelist_add(const wallet_public::COMMAND_ASSETS_WHITELIST_ADD::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_ADD::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
if(!w.get_wallet()->add_custom_asset_id(req.asset_id, res.asset_descriptor))
{
res.status = API_RETURN_CODE_NOT_FOUND;
}
else
{
res.status = API_RETURN_CODE_OK;
}
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_assets_whitelist_remove(const wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
if(!w.get_wallet()->delete_custom_asset_id(req.asset_id))
{
res.status = API_RETURN_CODE_NOT_FOUND;
}
else
{
res.status = API_RETURN_CODE_OK;
}
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::rpc_destinations_to_currency_destination(const std::list<wallet_public::transfer_destination>& rpc_destinations, std::vector<currency::tx_destination_entry>& currency_destinations)
{
GET_WALLET();
std::vector<currency::tx_destination_entry>& dsts = currency_destinations;
for (auto it = rpc_destinations.begin(); it != rpc_destinations.end(); it++)
{
currency::tx_destination_entry de;
de.addr.resize(1);
std::string embedded_payment_id;
//check if address looks like wrapped address
WLT_THROW_IF_FALSE_WITH_CODE(!currency::is_address_like_wrapped(it->address), "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
WLT_THROW_IF_FALSE_WITH_CODE(!w.get_wallet()->get_transfer_address(it->address, de.addr.back(), embedded_payment_id), "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
WLT_THROW_IF_FALSE_WITH_CODE(embedded_payment_id.size() == 0, "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS", "WALLET_RPC_ERROR_CODE_WRONG_ADDRESS");
de.amount = it->amount;
de.asset_id = it->asset_id;
dsts.push_back(de);
}
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_assets_deploy(const wallet_public::COMMAND_ASSETS_DEPLOY::request& req, wallet_public::COMMAND_ASSETS_DEPLOY::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction result_tx;
std::vector<currency::tx_destination_entry> currency_destinations;
rpc_destinations_to_currency_destination(req.destinations, currency_destinations);
w.get_wallet()->deploy_new_asset(req.asset_descriptor, currency_destinations, result_tx, res.new_asset_id);
res.result_tx = currency::get_transaction_hash(result_tx);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_assets_emit(const wallet_public::COMMAND_ASSETS_EMIT::request& req, wallet_public::COMMAND_ASSETS_EMIT::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction result_tx;
std::vector<currency::tx_destination_entry> currency_destinations;
rpc_destinations_to_currency_destination(req.destinations, currency_destinations);
w.get_wallet()->emit_asset(req.asset_id, currency_destinations, result_tx);
res.result_tx = currency::get_transaction_hash(result_tx);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_assets_update(const wallet_public::COMMAND_ASSETS_UPDATE::request& req, wallet_public::COMMAND_ASSETS_UPDATE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
currency::transaction result_tx;
w.get_wallet()->update_asset(req.asset_id, req.asset_descriptor, result_tx);
res.result_tx = currency::get_transaction_hash(result_tx);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_mw_get_wallets(const wallet_public::COMMAND_MW_GET_WALLETS::request& req, wallet_public::COMMAND_MW_GET_WALLETS::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -1068,6 +1341,18 @@ namespace tools
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_proxy_to_daemon(const wallet_public::COMMAND_PROXY_TO_DAEMON::request& req, wallet_public::COMMAND_PROXY_TO_DAEMON::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
std::string buff = epee::string_encoding::base64_decode(req.base64_body);
w.get_wallet()->proxy_to_daemon(req.uri, buff, res.response_code, res.base64_body);
res.base64_body = epee::string_encoding::base64_encode(res.base64_body);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();

View file

@ -12,11 +12,11 @@
#include "wallet_public_structs_defs.h"
#include "wallet2.h"
#include "common/command_line.h"
#define ZANO_ACCESS_TOKEN "Zano-Access-Token"
namespace tools
{
struct i_wallet_provider
{
virtual void lock() {};
@ -82,12 +82,15 @@ namespace tools
const static command_line::arg_descriptor<std::string> arg_rpc_bind_ip;
const static command_line::arg_descriptor<std::string> arg_miner_text_info;
const static command_line::arg_descriptor<bool> arg_deaf_mode;
const static command_line::arg_descriptor<std::string> arg_jwt_secret;
static void init_options(boost::program_options::options_description& desc);
bool init(const boost::program_options::variables_map& vm);
bool run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address);
bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context);
void set_jwt_secret(const std::string& jwt);
const std::string& get_jwt_secret();
BEGIN_URI_MAP2_VIRTUAL()
BEGIN_JSON_RPC_MAP("/json_rpc")
@ -103,6 +106,8 @@ namespace tools
MAP_JON_RPC_WE("make_integrated_address", on_make_integrated_address, wallet_public::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS)
MAP_JON_RPC_WE("split_integrated_address", on_split_integrated_address, wallet_public::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS)
MAP_JON_RPC_WE("sweep_below", on_sweep_below, wallet_public::COMMAND_SWEEP_BELOW)
MAP_JON_RPC_WE("get_bare_outs_stats", on_get_bare_outs_stats, wallet_public::COMMAND_RPC_GET_BARE_OUTS_STATS)
MAP_JON_RPC_WE("sweep_bare_outs", on_sweep_bare_outs, wallet_public::COMMAND_RPC_SWEEP_BARE_OUTS)
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_LEGACY)
@ -112,39 +117,52 @@ namespace tools
MAP_JON_RPC_WE("get_mining_history", on_get_mining_history, wallet_public::COMMAND_RPC_GET_MINING_HISTORY)
MAP_JON_RPC_WE("register_alias", on_register_alias, wallet_public::COMMAND_RPC_REGISTER_ALIAS)
//contracts API
MAP_JON_RPC_WE("contracts_send_proposal", on_contracts_send_proposal, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL)
MAP_JON_RPC_WE("contracts_accept_proposal", on_contracts_accept_proposal, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL)
MAP_JON_RPC_WE("contracts_get_all", on_contracts_get_all, wallet_public::COMMAND_CONTRACTS_GET_ALL)
MAP_JON_RPC_WE("contracts_release", on_contracts_release, wallet_public::COMMAND_CONTRACTS_RELEASE)
MAP_JON_RPC_WE("contracts_request_cancel", on_contracts_request_cancel, wallet_public::COMMAND_CONTRACTS_REQUEST_CANCEL)
MAP_JON_RPC_WE("contracts_accept_cancel", on_contracts_accept_cancel, wallet_public::COMMAND_CONTRACTS_ACCEPT_CANCEL)
//MAP_JON_RPC_WE("contracts_send_proposal", on_contracts_send_proposal, wallet_public::COMMAND_CONTRACTS_SEND_PROPOSAL)
//MAP_JON_RPC_WE("contracts_accept_proposal", on_contracts_accept_proposal, wallet_public::COMMAND_CONTRACTS_ACCEPT_PROPOSAL)
//MAP_JON_RPC_WE("contracts_get_all", on_contracts_get_all, wallet_public::COMMAND_CONTRACTS_GET_ALL)
//MAP_JON_RPC_WE("contracts_release", on_contracts_release, wallet_public::COMMAND_CONTRACTS_RELEASE)
//MAP_JON_RPC_WE("contracts_request_cancel", on_contracts_request_cancel, wallet_public::COMMAND_CONTRACTS_REQUEST_CANCEL)
//MAP_JON_RPC_WE("contracts_accept_cancel", on_contracts_accept_cancel, wallet_public::COMMAND_CONTRACTS_ACCEPT_CANCEL)
//marketplace API
MAP_JON_RPC_WE("marketplace_get_offers_ex", on_marketplace_get_my_offers, wallet_public::COMMAND_MARKETPLACE_GET_MY_OFFERS)
MAP_JON_RPC_WE("marketplace_push_offer", on_marketplace_push_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_OFFER)
MAP_JON_RPC_WE("marketplace_push_update_offer", on_marketplace_push_update_offer, wallet_public::COMMAND_MARKETPLACE_PUSH_UPDATE_OFFER)
MAP_JON_RPC_WE("marketplace_cancel_offer", on_marketplace_cancel_offer, wallet_public::COMMAND_MARKETPLACE_CANCEL_OFFER)
//HTLC API
MAP_JON_RPC_WE("atomics_create_htlc_proposal", on_create_htlc_proposal, wallet_public::COMMAND_CREATE_HTLC_PROPOSAL)
MAP_JON_RPC_WE("atomics_get_list_of_active_htlc", on_get_list_of_active_htlc, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC)
MAP_JON_RPC_WE("atomics_redeem_htlc", on_redeem_htlc, wallet_public::COMMAND_REDEEM_HTLC)
MAP_JON_RPC_WE("atomics_check_htlc_redeemed", on_check_htlc_redeemed, wallet_public::COMMAND_CHECK_HTLC_REDEEMED)
//MAP_JON_RPC_WE("atomics_create_htlc_proposal", on_create_htlc_proposal, wallet_public::COMMAND_CREATE_HTLC_PROPOSAL)
//MAP_JON_RPC_WE("atomics_get_list_of_active_htlc", on_get_list_of_active_htlc, wallet_public::COMMAND_GET_LIST_OF_ACTIVE_HTLC)
//MAP_JON_RPC_WE("atomics_redeem_htlc", on_redeem_htlc, wallet_public::COMMAND_REDEEM_HTLC)
//MAP_JON_RPC_WE("atomics_check_htlc_redeemed", on_check_htlc_redeemed, wallet_public::COMMAND_CHECK_HTLC_REDEEMED)
//IONIC_SWAPS API
MAP_JON_RPC_WE("ionic_swap_generate_proposal", on_ionic_swap_generate_proposal, wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL)
MAP_JON_RPC_WE("ionic_swap_get_proposal_info", on_ionic_swap_get_proposal_info, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO)
MAP_JON_RPC_WE("ionic_swap_accept_proposal", on_ionic_swap_accept_proposal, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL)
MAP_JON_RPC_WE("ionic_swap_generate_proposal", on_ionic_swap_generate_proposal, wallet_public::COMMAND_IONIC_SWAP_GENERATE_PROPOSAL)
MAP_JON_RPC_WE("ionic_swap_get_proposal_info", on_ionic_swap_get_proposal_info, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO)
MAP_JON_RPC_WE("ionic_swap_accept_proposal", on_ionic_swap_accept_proposal, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL)
// Assets API
MAP_JON_RPC_WE("assets_whitelist_get", on_assets_whitelist_get, wallet_public::COMMAND_ASSETS_WHITELIST_GET)
MAP_JON_RPC_WE("assets_whitelist_add", on_assets_whitelist_add, wallet_public::COMMAND_ASSETS_WHITELIST_ADD)
MAP_JON_RPC_WE("assets_whitelist_remove", on_assets_whitelist_remove, wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE)
MAP_JON_RPC_WE("deploy_asset", on_assets_deploy, wallet_public::COMMAND_ASSETS_DEPLOY)
MAP_JON_RPC_WE("emit_asset", on_assets_emit, wallet_public::COMMAND_ASSETS_EMIT)
MAP_JON_RPC_WE("update_asset", on_assets_update, wallet_public::COMMAND_ASSETS_UPDATE)
//MULTIWALLET APIs
MAP_JON_RPC_WE("mw_get_wallets", on_mw_get_wallets, wallet_public::COMMAND_MW_GET_WALLETS)
MAP_JON_RPC_WE("mw_select_wallet", on_mw_select_wallet, wallet_public::COMMAND_MW_SELECT_WALLET)
MAP_JON_RPC_WE("mw_get_wallets", on_mw_get_wallets, wallet_public::COMMAND_MW_GET_WALLETS)
MAP_JON_RPC_WE("mw_select_wallet", on_mw_select_wallet, wallet_public::COMMAND_MW_SELECT_WALLET)
//basic crypto operations
MAP_JON_RPC_WE("sign_message", on_sign_message, wallet_public::COMMAND_SIGN_MESSAGE)
MAP_JON_RPC_WE("encrypt_data", on_encrypt_data, wallet_public::COMMAND_ENCRYPT_DATA)
MAP_JON_RPC_WE("decrypt_data", on_decrypt_data, wallet_public::COMMAND_DECRYPT_DATA)
END_JSON_RPC_MAP()
MAP_JON_RPC_WE("sign_message", on_sign_message, wallet_public::COMMAND_SIGN_MESSAGE)
MAP_JON_RPC_WE("encrypt_data", on_encrypt_data, wallet_public::COMMAND_ENCRYPT_DATA)
MAP_JON_RPC_WE("decrypt_data", on_decrypt_data, wallet_public::COMMAND_DECRYPT_DATA)
//utility call
MAP_JON_RPC_WE("proxy_to_daemon", on_proxy_to_daemon, wallet_public::COMMAND_PROXY_TO_DAEMON)
END_JSON_RPC_MAP()
END_URI_MAP2()
bool auth_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context);
//json_rpc
bool on_getbalance(const wallet_public::COMMAND_RPC_GET_BALANCE::request& req, wallet_public::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_getaddress(const wallet_public::COMMAND_RPC_GET_ADDRESS::request& req, wallet_public::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
@ -160,6 +178,8 @@ namespace tools
bool on_make_integrated_address(const wallet_public::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::request& req, wallet_public::COMMAND_RPC_MAKE_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_split_integrated_address(const wallet_public::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::request& req, wallet_public::COMMAND_RPC_SPLIT_INTEGRATED_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
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_get_bare_outs_stats(const wallet_public::COMMAND_RPC_GET_BARE_OUTS_STATS ::request& req, wallet_public::COMMAND_RPC_GET_BARE_OUTS_STATS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_sweep_bare_outs(const wallet_public::COMMAND_RPC_SWEEP_BARE_OUTS::request& req, wallet_public::COMMAND_RPC_SWEEP_BARE_OUTS::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_LEGACY::request& req, wallet_public::COMMAND_RPC_SEARCH_FOR_TRANSACTIONS_LEGACY::response& res, epee::json_rpc::error& er, connection_context& cntx);
@ -189,6 +209,15 @@ namespace tools
bool on_ionic_swap_get_proposal_info(const wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO::request& req, wallet_public::COMMAND_IONIC_SWAP_GET_PROPOSAL_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_ionic_swap_accept_proposal(const wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL::request& req, wallet_public::COMMAND_IONIC_SWAP_ACCEPT_PROPOSAL::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_assets_whitelist_get(const wallet_public::COMMAND_ASSETS_WHITELIST_GET::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_GET::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_assets_whitelist_add(const wallet_public::COMMAND_ASSETS_WHITELIST_ADD::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_ADD::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_assets_whitelist_remove(const wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE::request& req, wallet_public::COMMAND_ASSETS_WHITELIST_REMOVE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_assets_deploy(const wallet_public::COMMAND_ASSETS_DEPLOY::request& req, wallet_public::COMMAND_ASSETS_DEPLOY::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_assets_emit(const wallet_public::COMMAND_ASSETS_EMIT::request& req, wallet_public::COMMAND_ASSETS_EMIT::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_assets_update(const wallet_public::COMMAND_ASSETS_UPDATE::request& req, wallet_public::COMMAND_ASSETS_UPDATE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_mw_get_wallets(const wallet_public::COMMAND_MW_GET_WALLETS::request& req, wallet_public::COMMAND_MW_GET_WALLETS::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_mw_select_wallet(const wallet_public::COMMAND_MW_SELECT_WALLET::request& req, wallet_public::COMMAND_MW_SELECT_WALLET::response& res, epee::json_rpc::error& er, connection_context& cntx);
@ -196,6 +225,7 @@ namespace tools
bool on_encrypt_data(const wallet_public::COMMAND_ENCRYPT_DATA::request& req, wallet_public::COMMAND_ENCRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_decrypt_data(const wallet_public::COMMAND_DECRYPT_DATA::request& req, wallet_public::COMMAND_DECRYPT_DATA::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_proxy_to_daemon(const wallet_public::COMMAND_PROXY_TO_DAEMON::request& req, wallet_public::COMMAND_PROXY_TO_DAEMON::response& res, epee::json_rpc::error& er, connection_context& cntx);
//std::shared_ptr<wallet2> get_wallet();
@ -203,6 +233,7 @@ namespace tools
//bool reset_active_wallet(std::shared_ptr<wallet2> w);
bool handle_command_line(const boost::program_options::variables_map& vm);
void rpc_destinations_to_currency_destination(const std::list<wallet_public::transfer_destination>& rpc_destinations, std::vector<currency::tx_destination_entry>& currency_destinations);
private:
std::shared_ptr<i_wallet_provider> m_pwallet_provider_sh_ptr;
@ -212,6 +243,8 @@ namespace tools
bool m_do_mint;
bool m_deaf;
uint64_t m_last_wallet_store_height;
std::string m_jwt_secret;
epee::misc_utils::expirating_set<std::string, uint64_t> m_jwt_used_salts;
};
} // namespace tools

View file

@ -546,13 +546,12 @@ bool wallets_manager::init_local_daemon()
CHECK_AND_ASSERT_AND_SET_GUI(res, "Failed to initialize core rpc server.");
LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_rpc_server.get_binded_port(), LOG_LEVEL_0);
m_ui_opt.rpc_port = m_rpc_server.get_binded_port();
//chain calls to rpc server
m_prpc_chain_handler = &m_wallet_rpc_server;
//disable this for main net until we get full support of authentication with network
#ifdef TESTNET
m_rpc_server.set_rpc_chain_handler(this);
#endif
LOG_PRINT_L0("Starting core rpc server...");
//dsi.text_state = "Starting core rpc server";
@ -572,6 +571,25 @@ bool wallets_manager::init_local_daemon()
return true;
}
std::string wallets_manager::setup_wallet_rpc(const std::string& jwt_secret)
{
#ifndef MOBILE_WALLET_BUILD
if (!jwt_secret.size())
{
//disabling wallet RPC
m_rpc_server.set_rpc_chain_handler(nullptr);
return WALLET_RPC_STATUS_OK;
}
//we don't override command line JWT secret
//if(!m_wallet_rpc_server.get_jwt_secret().size() )
m_wallet_rpc_server.set_jwt_secret(jwt_secret);
m_rpc_server.set_rpc_chain_handler(this);
#endif
return WALLET_RPC_STATUS_OK;
}
bool wallets_manager::deinit_local_daemon()
{
#ifndef MOBILE_WALLET_BUILD
@ -1025,7 +1043,6 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
w->set_use_deffered_global_outputs(m_use_deffered_global_outputs);
w->set_use_assets_whitelisting(true);
owr.wallet_id = m_wallet_id_counter++;
w->callback(std::shared_ptr<tools::i_wallet2_callback>(new i_wallet_to_i_backend_adapter(this, owr.wallet_id)));
@ -1057,10 +1074,11 @@ std::string wallets_manager::open_wallet(const std::wstring& path, const std::st
w->get_recent_transfers_history(owr.recent_history.history, 0, txs_to_return, owr.recent_history.total_history_items, owr.recent_history.last_item_index, exclude_mining_txs);
//w->get_unconfirmed_transfers(owr.recent_history.unconfirmed);
w->get_unconfirmed_transfers(owr.recent_history.history, exclude_mining_txs);
w->set_use_assets_whitelisting(true);
owr.wallet_local_bc_size = w->get_blockchain_current_size();
//workaround for missed fee
//owr.seed = w->get_account().get_seed_phrase();
owr.seed = w->get_account().get_seed_phrase("");
break;
}
catch (const tools::error::file_not_found& /**/)
@ -1170,7 +1188,7 @@ std::string wallets_manager::generate_wallet(const std::wstring& path, const std
{
w->generate(path, password, false);
w->set_minimum_height(m_last_daemon_height-1);
//owr.seed = w->get_account().get_seed_phrase();
owr.seed = w->get_account().get_seed_phrase("");
}
catch (const tools::error::file_exists&)
{
@ -1279,7 +1297,7 @@ std::string wallets_manager::restore_wallet(const std::wstring& path, const std:
{
bool is_tracking = currency::account_base::is_seed_tracking(seed_phrase);
w->restore(path, password, seed_phrase, is_tracking, seed_password);
//owr.seed = w->get_account().get_seed_phrase();
owr.seed = w->get_account().get_seed_phrase("");
}
catch (const tools::error::file_exists&)
{
@ -1645,11 +1663,10 @@ std::string wallets_manager::invoke(uint64_t wallet_id, std::string params)
epee::net_utils::http::http_request_info query_info = AUTO_VAL_INIT(query_info);
epee::net_utils::http::http_response_info response_info = AUTO_VAL_INIT(response_info);
epee::net_utils::connection_context_base stub_conn_context = AUTO_VAL_INIT(stub_conn_context);
std::string reference_stub;
bool call_found = false;
query_info.m_URI = "/json_rpc";
query_info.m_body = params;
wo.rpc_wrapper->handle_http_request_map(query_info, response_info, stub_conn_context, call_found, reference_stub);
wo.rpc_wrapper->handle_http_request_map(query_info, response_info, stub_conn_context, call_found);
return response_info.m_body;
}
@ -1880,6 +1897,7 @@ void wallets_manager::prepare_wallet_status_info(wallet_vs_options& wo, view::wa
wsi.wallet_id = wo.wallet_id;
wsi.is_alias_operations_available = !wo.has_related_alias_in_unconfirmed;
wo.w->get()->balance(wsi.balances, wsi.minied_total);
wsi.has_bare_unspent_outputs = wo.w->get()->has_bare_unspent_outputs();
}
std::string wallets_manager::check_available_sources(uint64_t wallet_id, std::list<uint64_t>& amounts)
{
@ -2103,10 +2121,10 @@ bool wallets_manager::on_mw_select_wallet(const tools::wallet_public::COMMAND_MW
return true;
}
void wallets_manager::lock()
{
#ifndef MOBILE_WALLET_BUILD
m_select_wallet_rpc_lock.lock();
{
SHARED_CRITICAL_REGION_LOCAL(m_wallets_lock);
auto it = m_wallets.find(m_rpc_selected_wallet_id);
@ -2123,6 +2141,7 @@ void wallets_manager::unlock()
{
#ifndef MOBILE_WALLET_BUILD
m_current_wallet_locked_object.reset();
m_select_wallet_rpc_lock.unlock();
#endif
}
std::shared_ptr<tools::wallet2> wallets_manager::get_wallet()

View file

@ -146,6 +146,8 @@ public:
std::string get_fav_offers(const std::list<bc_services::offer_id>& hashes, const bc_services::core_offers_filter& filter, std::list<bc_services::offer_details_ex>& offers);
std::string get_tx_pool_info(currency::COMMAND_RPC_GET_POOL_INFO::response& res);
std::string export_wallet_history(const view::export_wallet_info& ewi);
std::string setup_wallet_rpc(const std::string& jwt_secret);
#ifndef MOBILE_WALLET_BUILD
currency::core_rpc_server& get_rpc_server() { return m_rpc_server; }
#endif
@ -193,12 +195,12 @@ private:
bool do_exception_safe_call(guarded_code_t guarded_code, error_prefix_maker_t error_prefix_maker, std::string& api_return_code_result);
//----- i_backend_wallet_callback ------
virtual void on_new_block(size_t wallet_id, uint64_t height, const currency::block& block);
virtual void on_transfer2(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti, const std::list<tools::wallet_public::asset_balance_entry>& balances, uint64_t total_mined);
virtual void on_pos_block_found(size_t wallet_id, const currency::block& /*block*/);
virtual void on_sync_progress(size_t wallet_id, const uint64_t& /*percents*/);
virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti);
virtual void on_tor_status_change(size_t wallet_id, const std::string& state);
virtual void on_new_block(size_t wallet_id, uint64_t height, const currency::block& block) override;
virtual void on_transfer2(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti, const std::list<tools::wallet_public::asset_balance_entry>& balances, uint64_t total_mined) override;
virtual void on_pos_block_found(size_t wallet_id, const currency::block& /*block*/) override;
virtual void on_sync_progress(size_t wallet_id, const uint64_t& /*percents*/) override;
virtual void on_transfer_canceled(size_t wallet_id, const tools::wallet_public::wallet_transfer_info& wti) override;
virtual void on_tor_status_change(size_t wallet_id, const std::string& state) override;
virtual void on_mw_get_wallets(std::vector<tools::wallet_public::wallet_entry_info>& wallets) override;
virtual bool on_mw_select_wallet(uint64_t wallet_id) override;
@ -232,6 +234,8 @@ private:
std::mutex m_stop_singal_sent_mutex;
std::condition_variable m_stop_singal_sent_mutex_cv;
std::mutex m_select_wallet_rpc_lock;
view::i_view m_view_stub;
view::i_view* m_pview;
std::shared_ptr<tools::i_core_proxy> m_rpc_proxy;

View file

@ -69,8 +69,8 @@ bool block_template_against_txs_size::c1(currency::core& c, size_t ev_index, con
uint64_t top_block_height = bcs.get_top_block_height();
uint64_t blocksize_limit = bcs.get_current_comulative_blocksize_limit();
uint64_t base_block_reward_pow = get_base_block_reward(false, bcs.total_coins(), top_block_height + 1);
uint64_t base_block_reward_pos = get_base_block_reward(true, bcs.total_coins(), top_block_height + 1);
uint64_t base_block_reward_pow = get_base_block_reward(top_block_height + 1);
uint64_t base_block_reward_pos = base_block_reward_pow;
g_block_txs_fee = TESTS_DEFAULT_FEE; // passing an argument to custom_fill_block_template_func via global variable (not perfect but works well)
@ -91,13 +91,16 @@ bool block_template_against_txs_size::c1(currency::core& c, size_t ev_index, con
CHECK_AND_ASSERT_MES(r, false, "create_block_template failed, txs_total_size = " << txs_total_size);
CHECK_AND_ASSERT_MES(height == top_block_height + 1, false, "Incorrect height: " << height << ", expected: " << top_block_height + 1 << ", txs_total_size = " << txs_total_size);
uint64_t base_reward = 0;
uint64_t block_reward_without_fee = 0;
size_t cumulative_block_size = txs_total_size;
size_t coinbase_blob_size = get_object_blobsize(b.miner_tx);
if (coinbase_blob_size > CURRENCY_COINBASE_BLOB_RESERVED_SIZE)
cumulative_block_size += coinbase_blob_size;
r = bcs.validate_miner_transaction(b, cumulative_block_size, g_block_txs_fee, base_reward, bcs.total_coins());
r = bcs.calculate_block_reward_for_next_top_block(cumulative_block_size, block_reward_without_fee);
CHECK_AND_ASSERT_MES(r, false, "calculate_block_reward_for_next_top_block failed");
r = bcs.validate_miner_transaction(b.miner_tx, g_block_txs_fee, block_reward_without_fee);
CHECK_AND_ASSERT_MES(r, false, "validate_miner_transaction failed, txs_total_size = " << txs_total_size);
uint64_t generated_coins = get_outs_money_amount(b.miner_tx) - (is_pos != 0 ? boost::get<tx_out_bare>(b.miner_tx.vout.back()).amount : 0) - g_block_txs_fee / 2;

View file

@ -828,7 +828,7 @@ uint64_t test_generator::get_base_reward_for_next_block(const crypto::hash& head
auto it = m_blocks_info.find(head_id);
if (it == m_blocks_info.end())
return 0;
return get_base_block_reward(!pow, it->second.already_generated_coins, get_block_height(it->second.b));
return get_base_block_reward(get_block_height(it->second.b));
}
bool test_generator::find_nounce(currency::block& blk, std::vector<const block_info*>& blocks, wide_difficulty_type dif, uint64_t height) const
@ -2319,15 +2319,25 @@ bool check_ring_signature_at_gen_time(const std::vector<test_event_entry>& event
bool check_mixin_value_for_each_input(size_t mixin, const crypto::hash& tx_id, currency::core& c)
{
std::shared_ptr<const currency::transaction_chain_entry> ptce = c.get_blockchain_storage().get_tx_chain_entry(tx_id);
if (!ptce)
return false;
transaction tx_local;
const transaction* ptx = &tx_local;
for (size_t i = 0; i < ptce->tx.vin.size(); ++i)
std::shared_ptr<const currency::transaction_chain_entry> ptce = c.get_blockchain_storage().get_tx_chain_entry(tx_id);
if (ptce)
{
auto& input = ptce->tx.vin[i];
ptx = &ptce->tx;
}
else
{
if (!c.get_tx_pool().get_transaction(tx_id, tx_local))
return false;
}
for (size_t i = 0; i < ptx->vin.size(); ++i)
{
auto& input = ptx->vin[i];
const std::vector<currency::txout_ref_v>& key_offsets = get_key_offsets_from_txin_v(input);
CHECK_AND_ASSERT_MES(key_offsets.size() == mixin + 1, false, "for input #" << i << " mixin count is " << key_offsets.size() - 1 << ", expected is " << mixin);
CHECK_AND_ASSERT_MES(key_offsets.size() == mixin + 1, false, "for input #" << i << " ring size is " << key_offsets.size() << ", mixin count is " << key_offsets.size() - 1 << ", expected mixin count is " << mixin);
}
return true;

View file

@ -977,6 +977,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(multisig_out_make_and_spent_in_altchain);
GENERATE_AND_PLAY(multisig_unconfirmed_transfer_and_multiple_scan_pool_calls);
GENERATE_AND_PLAY(multisig_out_spent_in_altchain_case_b4);
GENERATE_AND_PLAY(multisig_n_participants_seq_signing);
GENERATE_AND_PLAY(ref_by_id_basics);
GENERATE_AND_PLAY(ref_by_id_mixed_inputs_types);
@ -1246,7 +1247,10 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(hard_fork_2_incorrect_alias_update<false>);
// HF4
// GENERATE_AND_PLAY_HF(hard_fork_4_consolidated_txs, "4"); TODO, doesn't work atm -- sowle
GENERATE_AND_PLAY_HF(hard_fork_4_consolidated_txs, "3-*");
GENERATE_AND_PLAY_HF(hardfork_4_wallet_transfer_with_mandatory_mixins, "3-*");
GENERATE_AND_PLAY(hardfork_4_wallet_sweep_bare_outs);
GENERATE_AND_PLAY_HF(hardfork_4_pop_tx_from_global_index, "4-*");
// atomics
GENERATE_AND_PLAY(atomic_simple_test);
@ -1270,6 +1274,9 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(zarcanum_block_with_txs);
GENERATE_AND_PLAY(asset_depoyment_and_few_zc_utxos);
GENERATE_AND_PLAY_HF(assets_and_pos_mining, "4-*");
GENERATE_AND_PLAY_HF(pos_fuse_test, "4-*");
GENERATE_AND_PLAY_HF(attachment_isolation_test, "4-*");

View file

@ -45,3 +45,4 @@
#include "multiassets_test.h"
#include "ionic_swap_tests.h"
#include "attachment_isolation_encryption_test.h"
#include "pos_fuse_test.h"

View file

@ -708,7 +708,7 @@ bool gen_no_attchments_in_coinbase::init_config_set_cp(currency::core& c, size_t
// different checkpoints due to different block versions for different hardforks -> different hashes
if (crc.is_hardfork_active_for_height(ZANO_HARDFORK_03, 11) && !crc.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 11))
{
m_checkpoints.add_checkpoint(12, "4e6055dda442e04b2feb70bc7245584742604e8515b8d2e1c3d46c26f758d59f");
m_checkpoints.add_checkpoint(12, "70fbbd33d88ccaa26f9fe64d102bcff2572494009339de9fab7158a40633fbb5");
}
else
{

View file

@ -1217,23 +1217,28 @@ bool hard_fork_2_alias_update_using_old_tx<before_hf_2>::c1(currency::core& c, s
//
// Send tx and print it's blob
// this code was used to generate old-style tx in develop branch, commit 36eabb916b95c7db06bdfb5d34d9820bd94b82df
// UPD: 2024-03-15 tx blob was updated as of commit f538fc3a7612e7ce86556a1cd2602400f6b4e9aa
//
transaction tx_upd = AUTO_VAL_INIT(tx_upd);
alice_wlt->request_alias_update(ai_upd, tx_upd, TESTS_DEFAULT_FEE, 0);
std::string tx_upd_hex = epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx_upd));
LOG_PRINT_L0("tx upd: " << ENDL << tx_upd_hex);
{
transaction tx_upd = AUTO_VAL_INIT(tx_upd);
alice_wlt->request_alias_update(ai_upd, tx_upd, TESTS_DEFAULT_FEE, 0);
std::string tx_upd_hex = epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(tx_upd));
LOG_PRINT_L0("tx upd: " << ENDL << tx_upd_hex);
}
*/
// use prepared tx blob
std::string tx_upd_hex("01010180988be49903011a0100000000000000ff593921b61d52e818058ef881764383fe9fb0cf4512da460daf477e3a216144000180d0dbc3f402037c2e68e9c60914d369dc53fcc91522dcec284e1b7c1604ccc3d8fcf67e2da0790003140a616c696365616c696365efdcf084d7af59e0d68e8bda3ff4514a02d812ccfd6a09f69811c5a6a1b035c9b1b2395fcd84283d02e2fc4f37395ac9d8f01ff3f1ad1b94a26aaf1c76bb39d00c48656c6c6f206d696e657221000118faf7b79730fd6c1ec5c918891e264e959749a0d8eebc7997b503bd185ef100fd9e0150c175e0f048ee729137ceed035e9145d7857eae9ab786dd319fe6520b16b0cc0d6a8766cd098fe5a42875243789cc3b4bf66ee0c12ff6ef2fc179d4cef50b0288360101f3012451b07e58e742c020d68e8ff6db2905fa3aad78806ba80b16f3c861ee09f79817ea1ec36b0e30c7be5412daf59bcbc34410461a0d126de4a2dd897ecf0200");
std::string tx_upd_hex("01010180988be49903011a01000000000000007bdeaff6ac11597e9fe397349dd2ecfcd6880cda9bbedaa67f759a5b95ba2ed9000180d0dbc3f4020335db05c510daddcb82257be70789650007ad2d567092ec1eb2a38a93ef8fa0070004140a616c696365616c696365efdcf084d7af59e0d68e8bda3ff4514a02d812ccfd6a09f69811c5a6a1b035c9b1b2395fcd84283d02e2fc4f37395ac9d8f01ff3f1ad1b94a26aaf1c76bb39d00c48656c6c6f206d696e6572210001c2537b8203e9c9981b87a3c63cc0c63e4ccc14ddd0309fdcee94664e4b3bc307ee438e90bb5720b7ac7cbec38fcac9c7aa5b9df02abd2fa1a58c580f9b3eaf0516116e8d89a67440aad0922a7e5dd88870e6f0af792a7af201ee21effd90cc6c7f1700000b02f37101016ed0997a3fe0c6bc47ffde14599a77697ba95c5c1489b65e5e54854146079f06569313d921f19ed2848cdccc8bad7f75fb46fc1608912365f569b7690703010b00");
std::string tx_upd_blob;
r = epee::string_tools::parse_hexstr_to_binbuff(tx_upd_hex, tx_upd_blob);
CHECK_AND_ASSERT_MES(r, false, "parse_hexstr_to_binbuff failed");
//r = t_unserializable_object_from_blob(tx_upd, tx_upd_blob);
//CHECK_AND_ASSERT_MES(r, false, "t_unserializable_object_from_blob failed");
crypto::hash tx_upd_hash{};
transaction tx_upd{};
CHECK_AND_ASSERT_MES(parse_and_validate_tx_from_blob(tx_upd_blob, tx_upd, tx_upd_hash), false, "parse_tx_form_blob failed");
//LOG_PRINT_L0("tx_upd: " << tx_upd_hash << ", json:" << ENDL << obj_to_json_str(tx_upd));
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
r = c.handle_incoming_tx(tx_upd_blob, tvc, false);
r = c.handle_incoming_tx(tx_upd, tvc, false, tx_upd_hash);
CHECK_AND_ASSERT_MES(r, false, "handle_incoming_tx failed");

View file

@ -242,4 +242,257 @@ bool hardfork_4_explicit_native_ids_in_outs::c1(currency::core& c, size_t ev_ind
{
return true;
}
*/
*/
//------------------------------------------------------------------------------
hardfork_4_wallet_transfer_with_mandatory_mixins::hardfork_4_wallet_transfer_with_mandatory_mixins()
{
REGISTER_CALLBACK_METHOD(hardfork_4_wallet_transfer_with_mandatory_mixins, c1);
REGISTER_CALLBACK_METHOD(hardfork_4_wallet_transfer_with_mandatory_mixins, configure_core);
}
bool hardfork_4_wallet_transfer_with_mandatory_mixins::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
test_chain_unit_enchanced::configure_core(c, ev_index, events); // call default
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
pc.hf4_minimum_mixins = CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE;
c.get_blockchain_storage().set_core_runtime_config(pc);
return true;
}
bool hardfork_4_wallet_transfer_with_mandatory_mixins::generate(std::vector<test_event_entry>& events) const
{
/* Test outline: make sure that after HF4 a normal transfer with CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE decoys goes normal.
* (It should also work prior to HF4.)
*/
bool r = false;
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
DO_CALLBACK(events, "configure_core"); // necessary for the test to be run by GENERATE_AND_PLAY_HF
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
MAKE_TX(events, tx_1, miner_acc, alice_acc, MK_TEST_COINS(10), blk_0r);
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1);
DO_CALLBACK(events, "c1");
return true;
}
bool hardfork_4_wallet_transfer_with_mandatory_mixins::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(10), 0, 0, 0, 0), false, "");
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(10), 0, MK_TEST_COINS(10), 0, 0), false, "");
alice_wlt->transfer(MK_TEST_COINS(9), m_accounts[BOB_ACC_IDX].get_public_address());
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
bob_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", MK_TEST_COINS(9), 0, 0, 0, 0), false, "");
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", 0, 0, 0, 0, 0), false, "");
bob_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", MK_TEST_COINS(9), 0, MK_TEST_COINS(9), 0, 0), false, "");
return true;
}
//------------------------------------------------------------------------------
hardfork_4_wallet_sweep_bare_outs::hardfork_4_wallet_sweep_bare_outs()
{
REGISTER_CALLBACK_METHOD(hardfork_4_wallet_sweep_bare_outs, c1);
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, 10);
}
bool hardfork_4_wallet_sweep_bare_outs::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make sure wallet2::sweep_bare_outs works well even if there's not enough outputs to mix
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
// rebuild genesis miner tx
std::vector<tx_destination_entry> destinations;
destinations.emplace_back(MK_TEST_COINS(23), alice_acc.get_public_address());
destinations.emplace_back(MK_TEST_COINS(23), bob_acc.get_public_address());
destinations.emplace_back(MK_TEST_COINS(55), bob_acc.get_public_address()); // this output is unique and doesn't have decoys
for (size_t i = 0; i < 10; ++i)
destinations.emplace_back(MK_TEST_COINS(23), miner_acc.get_public_address()); // decoys (later Alice will spend her output using mixins)
destinations.emplace_back(COIN, miner_acc.get_public_address()); // leftover amount will be also send to the last destination
CHECK_AND_ASSERT_MES(replace_coinbase_in_genesis_block(destinations, generator, events, blk_0), false, "");
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
DO_CALLBACK_PARAMS(events, "check_hardfork_active", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
DO_CALLBACK(events, "c1");
return true;
}
bool hardfork_4_wallet_sweep_bare_outs::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(23), UINT64_MAX, MK_TEST_COINS(23), 0, 0), false, "");
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
bob_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", MK_TEST_COINS(23 + 55), UINT64_MAX, MK_TEST_COINS(23 + 55), 0, 0), false, "");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
// 1. Try to sweep bare out for Alice (enough decoys to mix with)
std::vector<tools::wallet2::batch_of_bare_unspent_outs> tids_grouped_by_txs;
CHECK_AND_ASSERT_MES(alice_wlt->get_bare_unspent_outputs_stats(tids_grouped_by_txs), false, "");
size_t total_txs_sent = 0;
uint64_t total_amount_sent = 0;
uint64_t total_fee_spent = 0;
uint64_t total_bare_outs_sent = 0;
CHECK_AND_ASSERT_MES(alice_wlt->sweep_bare_unspent_outputs(m_accounts[ALICE_ACC_IDX].get_public_address(), tids_grouped_by_txs, total_txs_sent, total_amount_sent, total_fee_spent, total_bare_outs_sent), false, "");
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_txs_sent, 1);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_amount_sent, MK_TEST_COINS(23));
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_fee_spent, TESTS_DEFAULT_FEE);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_bare_outs_sent, 1);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
std::list<transaction> txs;
c.get_pool_transactions(txs);
auto& tx = txs.back();
CHECK_AND_ASSERT_MES(check_mixin_value_for_each_input(CURRENCY_DEFAULT_DECOY_SET_SIZE, get_transaction_hash(tx), c), false, "");
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
alice_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(23) - TESTS_DEFAULT_FEE, UINT64_MAX, MK_TEST_COINS(23) - TESTS_DEFAULT_FEE, 0, 0), false, "");
// 2. Try to sweep bare out for Bob (not enough decoys to mix with)
tids_grouped_by_txs.clear();
CHECK_AND_ASSERT_MES(bob_wlt->get_bare_unspent_outputs_stats(tids_grouped_by_txs), false, "");
CHECK_AND_ASSERT_MES(bob_wlt->sweep_bare_unspent_outputs(m_accounts[BOB_ACC_IDX].get_public_address(), tids_grouped_by_txs, total_txs_sent, total_amount_sent, total_fee_spent, total_bare_outs_sent), false, "");
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_txs_sent, 1);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_amount_sent, MK_TEST_COINS(23 + 55));
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_fee_spent, TESTS_DEFAULT_FEE);
CHECK_V_EQ_EXPECTED_AND_ASSERT(total_bare_outs_sent, 2);
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
txs.clear();
c.get_pool_transactions(txs);
auto& tx2 = txs.back();
CHECK_V_EQ_EXPECTED_AND_ASSERT(tx2.vin.size(), 2);
const txin_to_key &input_with_enough_decoys = boost::get<txin_to_key>(tx2.vin[0]).amount == MK_TEST_COINS(23) ? boost::get<txin_to_key>(tx2.vin[0]) : boost::get<txin_to_key>(tx2.vin[1]);
const txin_to_key &input_with_not_enough_decoys = boost::get<txin_to_key>(tx2.vin[0]).amount == MK_TEST_COINS(23) ? boost::get<txin_to_key>(tx2.vin[1]) : boost::get<txin_to_key>(tx2.vin[0]);
CHECK_V_EQ_EXPECTED_AND_ASSERT(input_with_enough_decoys.key_offsets.size(), CURRENCY_DEFAULT_DECOY_SET_SIZE + 1);
CHECK_V_EQ_EXPECTED_AND_ASSERT(input_with_not_enough_decoys.key_offsets.size(), 1);
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count());
bob_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", MK_TEST_COINS(23 + 55) - TESTS_DEFAULT_FEE, UINT64_MAX, MK_TEST_COINS(23 + 55) - TESTS_DEFAULT_FEE, 0, 0), false, "");
return true;
}
//------------------------------------------------------------------------------
hardfork_4_pop_tx_from_global_index::hardfork_4_pop_tx_from_global_index()
{
REGISTER_CALLBACK_METHOD(hardfork_4_pop_tx_from_global_index, c1);
}
bool hardfork_4_pop_tx_from_global_index::generate(std::vector<test_event_entry>& events) const
{
// Test idea: make sure that pop_transaction_from_global_index works for tx_out_zarcanum as well (m_db_outputs is consistent after pop_transaction_from_global_index() call)
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
DO_CALLBACK(events, "configure_core"); // default configure_core callback will initialize core runtime config with m_hardforks
REWIND_BLOCKS_N(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
DO_CALLBACK_PARAMS(events, "check_hardfork_active", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
MAKE_NEXT_BLOCK(events, blk_1a, blk_0r, miner_acc); // blk_1a will be the alt chain
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_1a)); // make sure now it's the main chain
MAKE_NEXT_BLOCK(events, blk_1, blk_0r, miner_acc);
MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner_acc); // this should trigger chain switching
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(blk_2)); // make sure it did
// during switching to the alternative chain pop_block_from_blockchain() -> ... -> pop_transaction_from_global_index() will be called
// but abort_transaction() will not, meaning m_db_outputs will be in incorrect state, if pop_transaction_from_global_index() hasn't properly pop all outs
// this will be checked later in c1
DO_CALLBACK(events, "c1");
return true;
}
bool hardfork_4_pop_tx_from_global_index::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
auto& bcs = c.get_blockchain_storage();
bool r = false;
//currency::outs_index_stat outs_stat{};
//bcs.get_outs_index_stat(outs_stat); // 24 - bad, 22 - good
COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::response res;
COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES_BY_AMOUNT::request req;
req.amount = 0;
req.i = 22;
CHECK_AND_ASSERT_MES(!bcs.get_global_index_details(req, res), false, "gindex 22 exists which is unexpected");
req.i = 21;
CHECK_AND_ASSERT_MES(bcs.get_global_index_details(req, res), false, "gindex 21 does not exist which is unexpected");
return true;
}

View file

@ -25,3 +25,27 @@ struct hardfork_4_explicit_native_ids_in_outs : public wallet_test
mutable uint64_t m_alice_initial_balance = 0;
};
struct hardfork_4_wallet_transfer_with_mandatory_mixins : public wallet_test
{
hardfork_4_wallet_transfer_with_mandatory_mixins();
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
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);
};
struct hardfork_4_wallet_sweep_bare_outs : public wallet_test
{
hardfork_4_wallet_sweep_bare_outs();
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);
};
struct hardfork_4_pop_tx_from_global_index : public wallet_test
{
hardfork_4_pop_tx_from_global_index();
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

@ -178,7 +178,6 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
// Alice wants to trade with Bob, to exchange 10.0 TCT to 0.5 ZANO
view::ionic_swap_proposal_info proposal_details = AUTO_VAL_INIT(proposal_details);
proposal_details.fee_paid_by_a = TESTS_DEFAULT_FEE;
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
proposal_details.to_finalizer.push_back(view::asset_funds{ asset_id , assets_to_exchange });
proposal_details.to_initiator.push_back(view::asset_funds{ currency::native_coin_asset_id , native_coins_to_exchange });
@ -192,7 +191,6 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
if (proposal_decoded_info.to_finalizer != proposal_details.to_finalizer
|| proposal_decoded_info.to_initiator != proposal_details.to_initiator
|| proposal_decoded_info.fee_paid_by_a != proposal_details.fee_paid_by_a
|| proposal_decoded_info.mixins != proposal_details.mixins
)
{
CHECK_AND_ASSERT_MES(false, false, "proposal actual and proposals decoded mismatch");
@ -233,7 +231,6 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
//now Alice want to trade with Bob, to send 0.5 ZANO and get 10.0 TCT in exchange
view::ionic_swap_proposal_info proposal_details = AUTO_VAL_INIT(proposal_details);
proposal_details.fee_paid_by_a = TESTS_DEFAULT_FEE;
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
proposal_details.to_finalizer.push_back(view::asset_funds{ currency::native_coin_asset_id , native_coins_to_exchange });
proposal_details.to_initiator.push_back(view::asset_funds{ asset_id , assets_to_exchange });
@ -247,7 +244,6 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
if (proposal_decoded_info.to_finalizer != proposal_details.to_finalizer
|| proposal_decoded_info.to_initiator != proposal_details.to_initiator
|| proposal_decoded_info.fee_paid_by_a != proposal_details.fee_paid_by_a
|| proposal_decoded_info.mixins != proposal_details.mixins
)
{
CHECK_AND_ASSERT_MES(false, false, "proposal actual and proposals decoded mismatch");
@ -387,7 +383,6 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
proposal_details.to_initiator.push_back(view::asset_funds{ asset_id, adb.total_max_supply });
proposal_details.to_finalizer.push_back(view::asset_funds{ native_coin_asset_id, MK_TEST_COINS(20) });
proposal_details.fee_paid_by_a = MK_TEST_COINS(1);
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
tools::wallet_public::ionic_swap_proposal proposal{};
alice_wlt->create_ionic_swap_proposal(proposal_details, m_accounts[BOB_ACC_IDX].get_public_address(), proposal);
@ -397,8 +392,7 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
CHECK_AND_ASSERT_MES(
proposal_decoded_info.to_finalizer == proposal_details.to_finalizer &&
proposal_decoded_info.to_initiator == proposal_details.to_initiator &&
proposal_decoded_info.fee_paid_by_a == proposal_details.fee_paid_by_a &&
proposal_decoded_info.mixins == proposal_details.mixins,
proposal_decoded_info.fee_paid_by_a == proposal_details.fee_paid_by_a,
false, "actual and decoded proposal mismatch \nproposal_decoded_info: "
<< epee::serialization::store_t_to_json(proposal_decoded_info) <<
"\nproposal_details" << epee::serialization::store_t_to_json(proposal_details));
@ -429,7 +423,6 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
proposal_details.to_initiator.push_back(view::asset_funds{ asset_id, adb.total_max_supply });
proposal_details.to_finalizer.push_back(view::asset_funds{ native_coin_asset_id, MK_TEST_COINS(20) });
proposal_details.fee_paid_by_a = MK_TEST_COINS(1);
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
proposal = tools::wallet_public::ionic_swap_proposal{};
carol_wlt->create_ionic_swap_proposal(proposal_details, m_accounts[ALICE_ACC_IDX].get_public_address(), proposal);
@ -439,8 +432,7 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
CHECK_AND_ASSERT_MES(
proposal_decoded_info.to_finalizer == proposal_details.to_finalizer &&
proposal_decoded_info.to_initiator == proposal_details.to_initiator &&
proposal_decoded_info.fee_paid_by_a == proposal_details.fee_paid_by_a &&
proposal_decoded_info.mixins == proposal_details.mixins,
proposal_decoded_info.fee_paid_by_a == proposal_details.fee_paid_by_a,
false, "actual and decoded proposal mismatch");
currency::transaction tx_is2{};

View file

@ -23,7 +23,7 @@ using namespace currency;
#define TMP_LOG_RESTORE
#endif
void exception_handler(){}
static void exception_handler(){}
//==============================================================================================================================
// helper routine: creates multisig-spending tx using a wallet and keys of other ms-participants, then sends it to the core proxy
@ -1638,7 +1638,7 @@ multisig_and_checkpoints::multisig_and_checkpoints()
bool multisig_and_checkpoints::set_cp(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
currency::checkpoints checkpoints;
checkpoints.add_checkpoint(15, "6f9194c144afd73077478e7f04e947c50160b5673558e6f696a4f662a3ca261e");
checkpoints.add_checkpoint(15, "fda3e645fbfd0f4852aa68e6ad021c9005c9faf2d7ba6b1b3c8e24efb9c0e8d0");
c.set_checkpoints(std::move(checkpoints));
return true;

View file

@ -0,0 +1,98 @@
// Copyright (c) 2014-2022 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chaingen.h"
#include "pos_fuse_test.h"
#include "wallet_test_core_proxy.h"
#include "random_helper.h"
#include "wallet/wallet_debug_events_definitions.h"
using namespace currency;
using namespace currency;
pos_fuse_test::pos_fuse_test()
{
REGISTER_CALLBACK_METHOD(pos_fuse_test, c1);
REGISTER_CALLBACK_METHOD(pos_fuse_test, configure_core);
}
bool pos_fuse_test::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
wallet_test::configure_core(c, ev_index, events);
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
pc.max_pos_difficulty = wide_difficulty_type(1);
//currency::core_runtime_config pc2;
//pc2 = pc;
c.get_blockchain_storage().set_core_runtime_config(pc);
currency::core_runtime_config pc2 = c.get_blockchain_storage().get_core_runtime_config();
LOG_PRINT_L1("Difficulty: " << pc2.max_pos_difficulty);
return true;
}
bool pos_fuse_test::generate(std::vector<test_event_entry>& events) const
{
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 10);
DO_CALLBACK(events, "c1");
return true;
}
bool pos_fuse_test::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
bool r = false;
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
miner_wlt->refresh();
while (true)
{
miner_wlt->refresh();
wide_difficulty_type pos_diff = c.get_blockchain_storage().get_next_diff_conditional(true);
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed");
bool r = miner_wlt->try_mint_pos();
CHECK_AND_ASSERT_MES(r, false, "Failed ot mint pos block");
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
LOG_PRINT_MAGENTA("POS Difficulty: " << pos_diff << ", max allowed diff: " << pc.max_pos_difficulty, LOG_LEVEL_0);
if (pos_diff > pc.max_pos_difficulty)
{
break;
}
}
//check that PoW blocks not going
r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c);
CHECK_AND_ASSERT_MES(!r, false, "PoW block unexpectedly generated");
//check that PoS blocks not going
r = miner_wlt->try_mint_pos();
CHECK_AND_ASSERT_MES(!r, false, "PoS block unexpectedly mined");
try
{
miner_wlt->transfer(1000000, m_accounts[ALICE_ACC_IDX].get_public_address());
CHECK_AND_ASSERT_MES(false, false, "Transaction unexpectedly sent");
}
catch (...)
{
LOG_PRINT_L0("Expected exception catched");
}
return true;
}

View file

@ -0,0 +1,14 @@
// 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
#include "chaingen.h"
#include "wallet_tests_basic.h"
struct pos_fuse_test : public wallet_test
{
pos_fuse_test();
virtual bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
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

@ -939,7 +939,25 @@ bool gen_crypted_attachments::check_crypted_tx(currency::core& c, size_t ev_inde
std::vector<payload_items_v> at;
bool r = currency::decrypt_payload_items(true, *ptx_from_bc, bob_acc.get_keys(), at);
CHECK_EQ(r, true);
CHECK_EQ(at.size(), 8); // custom attachments: 1) tx_payer, 2) tx_comment, 3) std::string; system attachments: 4) tx_crypto_checksum; system extra: 5) tx pub key, 6) extra_attachment_info, 7) etc_tx_flags16_t
if (at.size() != 16)
{
std::stringstream ss;
for(auto& el : at)
ss << " " << el.type().name() << ENDL;
LOG_PRINT_RED("at.size() = " << at.size() << " : " << ENDL << ss.str(), LOG_LEVEL_0);
// expected items:
// public_key
// etc_tx_flags16_t
// tx_derivation_hint x 10
// extra_attachment_info
// tx_payer
// tx_comment
// tx_crypto_checksum
//
// total: 16
CHECK_AND_ASSERT_MES(false, false, "unexpected number of decrypted items");
}
currency::tx_payer decrypted_pr = AUTO_VAL_INIT(decrypted_pr);
r = get_type_in_variant_container(at, decrypted_pr);

View file

@ -9,6 +9,10 @@
# make it prominent in the GUI.
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
if(POLICY CMP0148)
cmake_policy(SET CMP0148 OLD)
endif()
# When other libraries are using a shared version of runtime libraries,
# Google Test also has to use one.
option(
@ -40,7 +44,6 @@ endif()
# ${gtest_BINARY_DIR}.
# Language "C" is required for find_package(Threads).
project(gtest CXX C)
cmake_minimum_required(VERSION 2.6.2)
if (COMMAND set_up_hermetic_build)
set_up_hermetic_build()

View file

@ -27,16 +27,24 @@
#include "wallet/plain_wallet_api.h"
#include "wallet/view_iface.h"
PUSH_VS_WARNINGS
DISABLE_VS_WARNINGS(4244)
#include "jwt-cpp/jwt.h"
POP_VS_WARNINGS
void test_plain_wallet()
{
//std::string res = plain_wallet::init("195.201.107.230", "33336", "E:\\tmp\\", 0);
std::string res = plain_wallet::init("127.0.0.1", "12111", "C:\\Users\\roky\\home\\", 0);
std::string res = plain_wallet::init("127.0.0.1", "12111", "C:\\Users\\roky\\home22\\", 0);
std::string res___ = plain_wallet::get_wallet_files();
uint64_t instance_id = 0;
res = plain_wallet::open("test_restored.zan", "111");
//res = plain_wallet::restore("heart level clear fate sorrow childhood sent fate ceiling party third steel came ask mix neither message already almost vast date glide tumble color okay space",
// "test_restored.zan", "111", "");
res = plain_wallet::open("test_restored_2.zan", "111");
//res = plain_wallet::restore("",
// "test_restored_2.zan", "111", "");
while(true)
@ -49,24 +57,23 @@ void test_plain_wallet()
break;
}
std::string invoke_body = "{\"method\":\"store\",\"params\":{}}";
//std::string res1 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
std::string res1 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\"method\":\"get_recent_txs_and_info\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}";
std::string res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\"method\":\"get_recent_txs_and_info2\",\"params\":{\"offset\":0,\"count\":30,\"update_provision_info\":true}}";
res2 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\"method\":\"getbalance\",\"params\":{}}";
std::string res3 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\"method\":\"getbalance\",\"params\":{}}";
invoke_body = "{\r\n \"method\": \"transfer\",\r\n \"params\": {\r\n \"destinations\": [\r\n {\r\n \"amount\": \"1000000000000\",\r\n \"address\": \"ZxD9oVwGwW6ULix9Pqttnr7JDpaoLvDVA1KJ9eA9KRxPMRZT5X7WwtU94XH1Z6q6XTMxNbHmbV2xfZ429XxV6fST2DxEg4BQV\",\r\n \"asset_id\": \"cc4e69455e63f4a581257382191de6856c2156630b3fba0db4bdd73ffcfb36b6\"\r\n }\r\n ],\r\n \"fee\": 10000000000,\r\n \"mixin\": 10,\r\n \"payment_id\": \"\",\r\n \"comment\": \"\",\r\n \"push_payer\": false,\r\n \"hide_receiver\": true\r\n }\r\n}";
std::string res4 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
invoke_body = "{\r\n \"method\": \"transfer\",\r\n \"params\": {\r\n \"destinations\": [\r\n {\r\n \"amount\": \"1000000000000\",\r\n \"address\": \"ZxD9oVwGwW6ULix9Pqttnr7JDpaoLvDVA1KJ9eA9KRxPMRZT5X7WwtU94XH1Z6q6XTMxNbHmbV2xfZ429XxV6fST2DxEg4BQV\" }\r\n ],\r\n \"fee\": 10000000000,\r\n \"mixin\": 10,\r\n \"payment_id\": \"\",\r\n \"comment\": \"\",\r\n \"push_payer\": false,\r\n \"hide_receiver\": true\r\n }\r\n}";
std::string res5 = plain_wallet::sync_call("invoke", instance_id, invoke_body);
LOG_PRINT_L0(res);
}

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<UseMultiToolTask>true</UseMultiToolTask>
<EnforceProcessCountAcrossBuilds>true</EnforceProcessCountAcrossBuilds>
<MultiProcMaxCount>11</MultiProcMaxCount>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,7 @@
call configure_local_paths_msvs2022.cmd
cd ..
@mkdir build_msvc2022_64
cd build_msvc2022_64
cmake -D TESTNET=FALSE -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D OPENSSL_ROOT_DIR="%OPENSSL_ROOT_DIR%" -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2019_64 -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.3" -G "Visual Studio 17 2022" -A x64 -T host=x64 ".."

View file

@ -0,0 +1,7 @@
call configure_local_paths_msvs2022.cmd
cd ..
@mkdir build_msvc2022_64_tn
cd build_msvc2022_64_tn
cmake -D TESTNET=TRUE -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D OPENSSL_ROOT_DIR="%OPENSSL_ROOT_DIR%" -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2019_64 -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.3" -G "Visual Studio 17 2022" -A x64 -T host=x64 ".."

View file

@ -27,7 +27,7 @@ function upload_build() # $1 - path to the file to be uploaded
counter=0
while [ ! -f DONE ]
do
if [ "$counter" -ge 150 ]
if [ "$counter" -ge 500 ]
then
echo "ERROR: uploading is taking longer than expected"
touch STOP