forked from lthn/blockchain
Merge branch 'develop' into release
This commit is contained in:
commit
0f04017d2e
95 changed files with 5702 additions and 1329 deletions
|
|
@ -1,3 +1,6 @@
|
|||
|
||||
[](https://scan.coverity.com/projects/zanoproject)
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit a0ec89e46833e61d9b93850e85157d4bc93db1b2
|
||||
Subproject commit b7ed67543fefb0878dba1c70dea2a81201041314
|
||||
116
contrib/epee/include/misc_helpers.h
Normal file
116
contrib/epee/include/misc_helpers.h
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright (c) 2019, Zano Project
|
||||
// Copyright (c) 2006-2019, 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
|
||||
|
||||
#define COMBINE1(X,Y) X##Y // helper macro
|
||||
#define COMBINE(X,Y) COMBINE1(X,Y)
|
||||
#define _STR(X) #X
|
||||
#define STR(X) _STR(X)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define LOCAL_FUNCTION_DEF__ __FUNCTION__
|
||||
#define UNUSED_ATTRIBUTE
|
||||
#else
|
||||
#define LOCAL_FUNCTION_DEF__ __FUNCTION__
|
||||
#define UNUSED_ATTRIBUTE __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#define LOCATION_SS "[" << LOCAL_FUNCTION_DEF__ << ("] @ " __FILE__ ":" STR(__LINE__))
|
||||
#define LOCATION_STR (std::string("[") + LOCAL_FUNCTION_DEF__ + "] @ " __FILE__ ":" STR(__LINE__))
|
||||
|
||||
|
||||
//
|
||||
// Try-catch helpers
|
||||
//
|
||||
|
||||
#define TRY_ENTRY() try {
|
||||
#define CATCH_ALL_DO_NOTHING() }catch(...) {}
|
||||
|
||||
#define CATCH_ENTRY_CUSTOM(location, custom_code, return_val) } \
|
||||
catch(const std::exception& ex) \
|
||||
{ \
|
||||
(void)(ex); \
|
||||
LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \
|
||||
custom_code; \
|
||||
return return_val; \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \
|
||||
custom_code; \
|
||||
return return_val; \
|
||||
}
|
||||
#define CATCH_ENTRY(location, return_val) CATCH_ENTRY_CUSTOM(location, (void)0, return_val)
|
||||
#define CATCH_ENTRY2(return_val) CATCH_ENTRY_CUSTOM(LOCATION_SS, (void)0, return_val)
|
||||
|
||||
#define CATCH_ENTRY_L0(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L1(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L2(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L3(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L4(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
|
||||
/// @brief Catches TRY_ENTRY without returning
|
||||
/// @details Useful within a dtor - but only if nested within another try block
|
||||
/// (since we can still potentially throw here). See NESTED_*ENTRY()
|
||||
/// @todo Exception dispatcher class
|
||||
#define CATCH_ENTRY_NO_RETURN_CUSTOM(location, custom_code) } \
|
||||
catch(const std::exception& ex) \
|
||||
{ \
|
||||
(void)(ex); \
|
||||
LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \
|
||||
custom_code; \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \
|
||||
custom_code; \
|
||||
}
|
||||
|
||||
#define CATCH_ENTRY_NO_RETURN() CATCH_ENTRY_NO_RETURN_CUSTOM(LOCATION_SS, (void)0)
|
||||
|
||||
#define CATCH_ENTRY_WITH_FORWARDING_EXCEPTION() } \
|
||||
catch(const std::exception& ex) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << LOCATION_SS << "], what=" << ex.what()); \
|
||||
throw std::runtime_error(std::string("[EXCEPTION FORWARDED]: ") + ex.what()); \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << LOCATION_SS << "], generic unknown exception \"...\""); \
|
||||
throw std::runtime_error("[EXCEPTION FORWARDED]"); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define NESTED_TRY_ENTRY() try { TRY_ENTRY();
|
||||
|
||||
#define NESTED_CATCH_ENTRY(location) \
|
||||
CATCH_ENTRY_NO_RETURN_CUSTOM(location, {}); \
|
||||
} catch (...) {}
|
||||
|
||||
|
||||
|
||||
|
|
@ -393,7 +393,21 @@ namespace misc_utils
|
|||
|
||||
auto res = container.insert(typename t_container_type::value_type(key, AUTO_VAL_INIT(typename t_container_type::mapped_type())));
|
||||
return res.first->second;
|
||||
}
|
||||
}
|
||||
|
||||
template<class t_container_type>
|
||||
typename t_container_type::iterator it_get_or_insert_value_initialized(t_container_type& container, const typename t_container_type::key_type& key)
|
||||
{
|
||||
auto it = container.find(key);
|
||||
if (it != container.end())
|
||||
{
|
||||
return it;
|
||||
}
|
||||
|
||||
auto res = container.insert(typename t_container_type::value_type(key, AUTO_VAL_INIT(typename t_container_type::mapped_type())));
|
||||
return res.first;
|
||||
}
|
||||
|
||||
} // namespace misc_utils
|
||||
} // namespace epee
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// Copyright (c) 2019, Zano Project
|
||||
// Copyright (c) 2019, anonimal <anonimal@zano.org>
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
|
|
@ -59,6 +60,7 @@ PUSH_VS_WARNINGS
|
|||
DISABLE_VS_WARNINGS(4100)
|
||||
|
||||
|
||||
#include "misc_helpers.h"
|
||||
#include "static_initializer.h"
|
||||
#include "string_tools.h"
|
||||
#include "time_helper.h"
|
||||
|
|
@ -106,21 +108,6 @@ DISABLE_VS_WARNINGS(4100)
|
|||
#endif
|
||||
|
||||
|
||||
#define COMBINE1(X,Y) X##Y // helper macro
|
||||
#define COMBINE(X,Y) COMBINE1(X,Y)
|
||||
#define _STR(X) #X
|
||||
#define STR(X) _STR(X)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define LOCAL_FUNCTION_DEF__ __FUNCTION__
|
||||
#define UNUSED_ATTRIBUTE
|
||||
#else
|
||||
#define LOCAL_FUNCTION_DEF__ __PRETTY_FUNCTION__
|
||||
#define UNUSED_ATTRIBUTE __attribute__((unused))
|
||||
#endif
|
||||
|
||||
#define LOCATION_SS "[" << LOCAL_FUNCTION_DEF__ << ("] @ " __FILE__ ":" STR(__LINE__))
|
||||
|
||||
#if !defined(DISABLE_RELEASE_LOGGING)
|
||||
#define ENABLE_LOGGING_INTERNAL
|
||||
#endif
|
||||
|
|
@ -131,28 +118,29 @@ DISABLE_VS_WARNINGS(4100)
|
|||
epee::log_space::log_singletone::enable_channel(ch_name); return true; \
|
||||
});
|
||||
|
||||
|
||||
#if defined(ENABLE_LOGGING_INTERNAL)
|
||||
|
||||
#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
|
||||
{std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);}}
|
||||
{TRY_ENTRY();std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}}
|
||||
|
||||
#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
|
||||
{std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}}
|
||||
{TRY_ENTRY();std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}}
|
||||
|
||||
#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
|
||||
{std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}}
|
||||
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}}
|
||||
|
||||
#define LOG_PRINT_CHANNEL2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
|
||||
{std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);}}
|
||||
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}}
|
||||
|
||||
#define LOG_PRINT_CHANNEL_COLOR2(log_channel, log_name, x, y, color) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
|
||||
{std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name);}}
|
||||
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name);CATCH_ALL_DO_NOTHING();}}
|
||||
|
||||
#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
|
||||
{std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);}}
|
||||
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);CATCH_ALL_DO_NOTHING();}}
|
||||
|
||||
#define LOG_ERROR2(log_name, x) { \
|
||||
std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << "[ERROR] Location: " << std::endl << LOCATION_SS << epee::misc_utils::get_callstack() << " Message:" << std::endl << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str(), LOG_LEVEL_0, epee::log_space::console_color_red, true, log_name); LOCAL_ASSERT(0); epee::log_space::increase_error_count(LOG_DEFAULT_CHANNEL); }
|
||||
TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << "[ERROR] Location: " << std::endl << LOCATION_SS << epee::misc_utils::get_callstack() << " Message:" << std::endl << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str(), LOG_LEVEL_0, epee::log_space::console_color_red, true, log_name); LOCAL_ASSERT(0); epee::log_space::increase_error_count(LOG_DEFAULT_CHANNEL);CATCH_ALL_DO_NOTHING();}
|
||||
|
||||
#define LOG_FRAME2(log_name, x, y) epee::log_space::log_frame frame(x, y, log_name)
|
||||
|
||||
|
|
@ -212,67 +200,6 @@ DISABLE_VS_WARNINGS(4100)
|
|||
|
||||
#define ENDL std::endl
|
||||
|
||||
#define TRY_ENTRY() try {
|
||||
#define CATCH_ENTRY_CUSTOM(location, custom_code, return_val) } \
|
||||
catch(const std::exception& ex) \
|
||||
{ \
|
||||
(void)(ex); \
|
||||
LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \
|
||||
custom_code; \
|
||||
return return_val; \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \
|
||||
custom_code; \
|
||||
return return_val; \
|
||||
}
|
||||
#define CATCH_ENTRY(location, return_val) CATCH_ENTRY_CUSTOM(location, (void)0, return_val)
|
||||
#define CATCH_ENTRY2(return_val) CATCH_ENTRY_CUSTOM(LOCATION_SS, (void)0, return_val)
|
||||
|
||||
#define CATCH_ENTRY_L0(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L1(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L2(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L3(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
#define CATCH_ENTRY_L4(location, return_val) CATCH_ENTRY(location, return_val)
|
||||
|
||||
/// @brief Catches TRY_ENTRY without returning
|
||||
/// @details Useful within a dtor - but only if nested within another try block
|
||||
/// (since we can still potentially throw here). See NESTED_*ENTRY()
|
||||
/// @todo Exception dispatcher class
|
||||
#define CATCH_ENTRY_NO_RETURN(location, custom_code) } \
|
||||
catch(const std::exception& ex) \
|
||||
{ \
|
||||
(void)(ex); \
|
||||
LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \
|
||||
custom_code; \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \
|
||||
custom_code; \
|
||||
}
|
||||
|
||||
|
||||
#define CATCH_ENTRY_WITH_FORWARDING_EXCEPTION() } \
|
||||
catch(const std::exception& ex) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << LOCATION_SS << "], what=" << ex.what()); \
|
||||
throw std::runtime_error(std::string("[EXCEPTION FORWARDED]: ") + ex.what()); \
|
||||
} \
|
||||
catch(...) \
|
||||
{ \
|
||||
LOG_ERROR("Exception at [" << LOCATION_SS << "], generic unknown exception \"...\""); \
|
||||
throw std::runtime_error("[EXCEPTION FORWARDED]"); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define NESTED_TRY_ENTRY() try { TRY_ENTRY();
|
||||
|
||||
#define NESTED_CATCH_ENTRY(location) \
|
||||
CATCH_ENTRY_NO_RETURN(location, {}); \
|
||||
} catch (...) {}
|
||||
|
||||
#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());}
|
||||
|
||||
|
|
|
|||
|
|
@ -213,8 +213,8 @@ class boosted_tcp_server
|
|||
return true;
|
||||
}
|
||||
|
||||
idle_callback_conext_base(boost::asio::io_service& io_serice)
|
||||
: m_timer(io_serice)
|
||||
idle_callback_conext_base(boost::asio::io_service& io_serice): m_timer(io_serice),
|
||||
m_period(0)
|
||||
{
|
||||
}
|
||||
boost::asio::deadline_timer m_timer;
|
||||
|
|
@ -254,7 +254,14 @@ class boosted_tcp_server
|
|||
if(!ptr->call_handler())
|
||||
return true;
|
||||
}
|
||||
catch(...) {
|
||||
catch(std::exception& e)
|
||||
{
|
||||
LOG_ERROR("exeption caught in boosted_tcp_server::global_timer_handler: " << e.what() << ENDL << "won't be called anymore");
|
||||
return true;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LOG_ERROR("unknown exeption caught in boosted_tcp_server::global_timer_handler, it won't be called anymore");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -870,8 +870,10 @@ using namespace std;
|
|||
if(!u_c.port)
|
||||
u_c.port = 80;//default for http
|
||||
|
||||
res = tr.connect(u_c.host, static_cast<int>(u_c.port), timeout);
|
||||
CHECK_AND_ASSERT_MES(res, false, "failed to connect " << u_c.host << ":" << u_c.port);
|
||||
if (!tr.connect(u_c.host, static_cast<int>(u_c.port), timeout))
|
||||
{
|
||||
LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port);
|
||||
}
|
||||
}
|
||||
|
||||
return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ namespace epee
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
//basic helpers for pod-to-hex serialization
|
||||
template<class t_pod_type>
|
||||
std::string transform_t_pod_to_str(const t_pod_type & a)
|
||||
|
|
@ -61,7 +62,8 @@ namespace epee
|
|||
t_pod_type transform_str_to_t_pod(const std::string& a)
|
||||
{
|
||||
t_pod_type res = AUTO_VAL_INIT(res);
|
||||
epee::string_tools::hex_to_pod(a, res);
|
||||
if (!epee::string_tools::hex_to_pod(a, res))
|
||||
throw std::runtime_error(std::string("Unable to transform \"") + a + "\" to pod type " + typeid(t_pod_type).name());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
41
contrib/epee/include/serialization/keyvalue_hexemizer.h
Normal file
41
contrib/epee/include/serialization/keyvalue_hexemizer.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2006-2019, 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 "keyvalue_serialization.h"
|
||||
namespace epee
|
||||
{
|
||||
|
||||
struct hexemizer
|
||||
{
|
||||
std::string blob;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_BLOB_AS_HEX_STRING(blob)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// Copyright (c) 2019, anonimal, <anonimal@zano.org>
|
||||
// Copyright (c) 2019, Zano Project
|
||||
// Copyright (c) 2019, anonimal, <anonimal@zano.org>
|
||||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
|
|
@ -24,12 +25,7 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef __WINH_OBJ_H__
|
||||
#define __WINH_OBJ_H__
|
||||
#pragma once
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
|
|
@ -40,7 +36,7 @@
|
|||
|
||||
#include "singleton.h"
|
||||
#include "static_initializer.h"
|
||||
|
||||
#include "misc_helpers.h"
|
||||
|
||||
//#define DISABLE_DEADLOCK_GUARD
|
||||
|
||||
|
|
@ -57,9 +53,6 @@
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
|
|
@ -526,9 +519,11 @@ namespace epee
|
|||
<< prev_it->second.func_name << " @ " << prev_it->second.block_location << std::endl << " |" << std::endl << " V" << std::endl;
|
||||
prev_it = current_it;
|
||||
}
|
||||
|
||||
ss << prev_it->second.thread_name << "(tid:" << prev_it->first << ") blocked by locker \"" << lock_name << "(owned by " << (*threads_chain.begin())->second.thread_name << " tid:" << (*threads_chain.begin())->first << ")] at "
|
||||
<< func_name << " @ " << location << std::endl;
|
||||
if (prev_it != m_thread_owned_locks.end())
|
||||
{
|
||||
ss << prev_it->second.thread_name << "(tid:" << prev_it->first << ") blocked by locker \"" << lock_name << "(owned by " << (*threads_chain.begin())->second.thread_name << " tid:" << (*threads_chain.begin())->first << ")] at "
|
||||
<< func_name << " @ " << location << std::endl;
|
||||
}
|
||||
m_deadlock_journal.push_back(ss.str());
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
|
|
@ -605,14 +600,9 @@ namespace epee
|
|||
|
||||
~guarded_critical_region_t()
|
||||
{
|
||||
// TODO(unassigned): because one cannot forward-declare macros,
|
||||
// the circular dependency created by misc_log_ex will not
|
||||
// allow us to actually use these substitutions.
|
||||
//NESTED_TRY_ENTRY();
|
||||
|
||||
TRY_ENTRY();
|
||||
unlock();
|
||||
|
||||
//NESTED_CATCH_ENTRY(__func__);
|
||||
CATCH_ALL_DO_NOTHING();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
|
|
@ -708,6 +698,9 @@ namespace epee
|
|||
#define CRITICAL_REGION_BEGIN1(x) CRITICAL_REGION_BEGIN_VAR(x, critical_region_var1)
|
||||
#define CRITICAL_REGION_END() }
|
||||
|
||||
|
||||
#define CIRITCAL_OPERATION(obj,op) {obj##_lock.lock();obj . op;obj##_lock.unlock();}
|
||||
|
||||
#define SHARED_CRITICAL_REGION_LOCAL(x) boost::shared_lock< boost::shared_mutex > critical_region_var(x)
|
||||
#define EXCLUSIVE_CRITICAL_REGION_LOCAL(x) boost::unique_lock< boost::shared_mutex > critical_region_var(x)
|
||||
|
||||
|
|
@ -716,6 +709,3 @@ namespace epee
|
|||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ if(POLICY CMP0043)
|
|||
cmake_policy(SET CMP0043 OLD)
|
||||
endif()
|
||||
|
||||
|
||||
###########
|
||||
# using shared PCH -- this is unusual case for MSVC... so mystery, such hack, many wow. See also: https://stackoverflow.com/questions/645747/sharing-precompiled-headers-between-projects-in-visual-studio/4170902#4170902
|
||||
# define USE_PCH to YES for using precomiled headers
|
||||
|
|
|
|||
|
|
@ -89,8 +89,11 @@ namespace tools
|
|||
mutable performance_data m_gperformance_data;
|
||||
mutable std::unordered_map<container_handle, performance_data> m_performance_data_map;
|
||||
public:
|
||||
basic_db_accessor(std::shared_ptr<i_db_backend> backend, epee::shared_recursive_mutex& rwlock) :m_backend(backend), m_rwlock(rwlock), m_is_open(false)
|
||||
{}
|
||||
basic_db_accessor(std::shared_ptr<i_db_backend> backend, epee::shared_recursive_mutex& rwlock)
|
||||
: m_backend(backend), m_rwlock(rwlock), m_is_open(false)
|
||||
{
|
||||
}
|
||||
|
||||
~basic_db_accessor()
|
||||
{
|
||||
close();
|
||||
|
|
@ -239,8 +242,11 @@ namespace tools
|
|||
bool close()
|
||||
{
|
||||
m_is_open = false;
|
||||
if (!m_backend)
|
||||
return true;
|
||||
return m_backend->close();
|
||||
}
|
||||
|
||||
bool open(const std::string& path, uint64_t cache_sz = CACHE_SIZE)
|
||||
{
|
||||
bool r = m_backend->open(path, cache_sz);
|
||||
|
|
@ -513,7 +519,9 @@ namespace tools
|
|||
|
||||
~basic_key_value_accessor()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
bdb.unbind_parent_container(this);
|
||||
CATCH_ALL_DO_NOTHING();
|
||||
}
|
||||
|
||||
virtual bool on_write_transaction_begin()
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
#define BUF_SIZE 1024
|
||||
|
||||
#define CHECK_AND_ASSERT_MESS_LMDB_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(res == MDB_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
#define CHECK_AND_ASSERT_THROW_MESS_LMDB_DB(rc, mess) CHECK_AND_ASSERT_THROW_MES(res == MDB_SUCCESS, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
#define CHECK_AND_ASSERT_MESS_LMDB_DB(rc, ret, mess) CHECK_AND_ASSERT_MES(rc == MDB_SUCCESS, ret, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
#define CHECK_AND_ASSERT_THROW_MESS_LMDB_DB(rc, mess) CHECK_AND_ASSERT_THROW_MES(rc == MDB_SUCCESS, "[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
#define ASSERT_MES_AND_THROW_LMDB(rc, mess) ASSERT_MES_AND_THROW("[DB ERROR]:(" << rc << ")" << mdb_strerror(rc) << ", [message]: " << mess);
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
|
|
|
|||
|
|
@ -15,27 +15,34 @@ namespace tools
|
|||
namespace db
|
||||
{
|
||||
inline
|
||||
bool select_db_engine_from_arg(const boost::program_options::variables_map& vm, tools::db::basic_db_accessor& rdb)
|
||||
bool select_db_engine_from_arg(const boost::program_options::variables_map& vm, tools::db::basic_db_accessor& rdb)
|
||||
{
|
||||
if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_LMDB)
|
||||
try
|
||||
{
|
||||
rdb.reset_backend(std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend));
|
||||
if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_LMDB)
|
||||
{
|
||||
rdb.reset_backend(std::shared_ptr<tools::db::i_db_backend>(new tools::db::lmdb_db_backend));
|
||||
return true;
|
||||
}
|
||||
else if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_MDBX)
|
||||
{
|
||||
#ifdef ENABLED_ENGINE_MDBX
|
||||
rdb.reset_backend(std::shared_ptr<tools::db::i_db_backend>(new tools::db::mdbx_db_backend));
|
||||
return true;
|
||||
#else
|
||||
LOG_PRINT_L0(" DB ENGINE: " << ARG_DB_ENGINE_MDBX << " is not suported by this build(see DISABLE_MDBX cmake option), STOPPING");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else if (command_line::get_arg(vm, command_line::arg_db_engine) == ARG_DB_ENGINE_MDBX)
|
||||
catch (...)
|
||||
{
|
||||
#ifdef ENABLED_ENGINE_MDBX
|
||||
rdb.reset_backend(std::shared_ptr<tools::db::i_db_backend>(new tools::db::mdbx_db_backend));
|
||||
#else
|
||||
LOG_PRINT_L0(" DB ENGINE: " << ARG_DB_ENGINE_MDBX << " is not suported by this build(see DISABLE_MDBX cmake option), STOPPING");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_PRINT_RED_L0(" UNKNOWN DB ENGINE: " << command_line::get_arg(vm, command_line::arg_db_engine) << ", STOPPING");
|
||||
LOG_ERROR("internal error: arg_db_engine command-line option could not be read (exception caught)");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
LOG_PRINT_RED_L0(" UNKNOWN DB ENGINE: " << command_line::get_arg(vm, command_line::arg_db_engine) << ", STOPPING");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ namespace bc_services
|
|||
//------------------------------------------------------------------
|
||||
bc_offers_service::~bc_offers_service()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
if (!m_deinitialized)
|
||||
deinit();
|
||||
CATCH_ENTRY_NO_RETURN();
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool bc_offers_service::init(const std::string& config_folder, const boost::program_options::variables_map& vm)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "basic_pow_helpers.h"
|
||||
#include "version.h"
|
||||
#include "tx_semantic_validation.h"
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "core"
|
||||
|
|
@ -152,6 +153,7 @@ void blockchain_storage::init_options(boost::program_options::options_descriptio
|
|||
{
|
||||
command_line::add_arg(desc, arg_db_cache_l1);
|
||||
command_line::add_arg(desc, arg_db_cache_l2);
|
||||
command_line::add_arg(desc, command_line::arg_db_engine);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
uint64_t blockchain_storage::get_block_h_older_then(uint64_t timestamp) const
|
||||
|
|
@ -437,7 +439,7 @@ bool blockchain_storage::deinit()
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::pop_block_from_blockchain()
|
||||
bool blockchain_storage::pop_block_from_blockchain(transactions_map& onboard_transactions)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
||||
|
|
@ -447,7 +449,7 @@ bool blockchain_storage::pop_block_from_blockchain()
|
|||
CHECK_AND_ASSERT_MES(bei_ptr.get(), false, "pop_block_from_blockchain: can't pop from blockchain");
|
||||
|
||||
uint64_t fee_total = 0;
|
||||
bool r = purge_block_data_from_blockchain(bei_ptr->bl, bei_ptr->bl.tx_hashes.size(), fee_total);
|
||||
bool r = purge_block_data_from_blockchain(bei_ptr->bl, bei_ptr->bl.tx_hashes.size(), fee_total, onboard_transactions);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to purge_block_data_from_blockchain for block " << get_block_hash(bei_ptr->bl) << " on height " << h);
|
||||
|
||||
pop_block_from_per_block_increments(bei_ptr->height);
|
||||
|
|
@ -647,7 +649,7 @@ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const trans
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee)
|
||||
bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee, transaction& tx_)
|
||||
{
|
||||
fee = 0;
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
|
|
@ -655,6 +657,7 @@ bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& t
|
|||
auto tx_res_ptr = m_db_transactions.find(tx_id);
|
||||
CHECK_AND_ASSERT_MES(tx_res_ptr != m_db_transactions.end(), false, "transaction " << tx_id << " is not found in blockchain index!!");
|
||||
const transaction& tx = tx_res_ptr->tx;
|
||||
tx_ = tx;
|
||||
|
||||
fee = get_tx_fee(tx_res_ptr->tx);
|
||||
purge_transaction_keyimages_from_blockchain(tx, true);
|
||||
|
|
@ -685,10 +688,11 @@ bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& t
|
|||
bool blockchain_storage::purge_block_data_from_blockchain(const block& b, size_t processed_tx_count)
|
||||
{
|
||||
uint64_t total_fee = 0;
|
||||
return purge_block_data_from_blockchain(b, processed_tx_count, total_fee);
|
||||
transactions_map onboard_transactions;
|
||||
return purge_block_data_from_blockchain(b, processed_tx_count, total_fee, onboard_transactions);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::purge_block_data_from_blockchain(const block& bl, size_t processed_tx_count, uint64_t& fee_total)
|
||||
bool blockchain_storage::purge_block_data_from_blockchain(const block& bl, size_t processed_tx_count, uint64_t& fee_total, transactions_map& onboard_transactions)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
fee_total = 0;
|
||||
|
|
@ -697,11 +701,13 @@ bool blockchain_storage::purge_block_data_from_blockchain(const block& bl, size_
|
|||
CHECK_AND_ASSERT_MES(processed_tx_count <= bl.tx_hashes.size(), false, "wrong processed_tx_count in purge_block_data_from_blockchain");
|
||||
for(size_t count = 0; count != processed_tx_count; count++)
|
||||
{
|
||||
res = purge_transaction_from_blockchain(bl.tx_hashes[(processed_tx_count -1)- count], fee) && res;
|
||||
transaction tx = AUTO_VAL_INIT(tx);
|
||||
res = purge_transaction_from_blockchain(bl.tx_hashes[(processed_tx_count -1)- count], fee, tx) && res;
|
||||
fee_total += fee;
|
||||
onboard_transactions[bl.tx_hashes[(processed_tx_count - 1) - count]] = tx;
|
||||
}
|
||||
|
||||
res = purge_transaction_from_blockchain(get_transaction_hash(bl.miner_tx), fee) && res;
|
||||
transaction tx = AUTO_VAL_INIT(tx);
|
||||
res = purge_transaction_from_blockchain(get_transaction_hash(bl.miner_tx), fee, tx) && res;
|
||||
return res;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
|
|
@ -864,20 +870,22 @@ bool blockchain_storage::get_block_by_height(uint64_t h, block &blk) const
|
|||
// invalid.push_back(v.first);
|
||||
// }
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height)
|
||||
bool blockchain_storage::rollback_blockchain_switching(std::list<block_ws_txs>& original_chain, size_t rollback_height)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_read_lock);
|
||||
//remove failed subchain
|
||||
for(size_t i = m_db_blocks.size()-1; i >=rollback_height; i--)
|
||||
{
|
||||
bool r = pop_block_from_blockchain();
|
||||
transactions_map ot;
|
||||
bool r = pop_block_from_blockchain(ot);
|
||||
CHECK_AND_ASSERT_MES(r, false, "PANIC!!! failed to remove block while chain switching during the rollback!");
|
||||
}
|
||||
//return back original chain
|
||||
BOOST_FOREACH(auto& bl, original_chain)
|
||||
BOOST_FOREACH(auto& oce, original_chain)
|
||||
{
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
bool r = handle_block_to_main_chain(bl, bvc);
|
||||
bvc.m_onboard_transactions.swap(oce.onboard_transactions);
|
||||
bool r = handle_block_to_main_chain(oce.b, bvc);
|
||||
CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC!!! failed to add (again) block while chain switching during the rollback!");
|
||||
}
|
||||
|
||||
|
|
@ -940,13 +948,15 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
|
|||
);
|
||||
|
||||
//disconnecting old chain
|
||||
std::list<block> disconnected_chain;
|
||||
std::list<block_ws_txs> disconnected_chain;
|
||||
for(size_t i = m_db_blocks.size()-1; i >=split_height; i--)
|
||||
{
|
||||
block b = m_db_blocks[i]->bl;
|
||||
bool r = pop_block_from_blockchain();
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to remove block " << get_block_hash(b) << " @ " << get_block_height(b) << " on chain switching");
|
||||
disconnected_chain.push_front(b);
|
||||
disconnected_chain.push_front(block_ws_txs());
|
||||
block_ws_txs& bwt = disconnected_chain.front();
|
||||
bwt.b = m_db_blocks[i]->bl;
|
||||
bool r = pop_block_from_blockchain(bwt.onboard_transactions);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to remove block " << get_block_hash(bwt.b) << " @ " << get_block_height(bwt.b) << " on chain switching");
|
||||
|
||||
CHECK_AND_ASSERT_MES(validate_blockchain_prev_links(), false, "EPIC FAIL!");
|
||||
}
|
||||
|
||||
|
|
@ -955,6 +965,7 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
|
|||
{
|
||||
auto ch_ent = *alt_ch_iter;
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
bvc.m_onboard_transactions = ch_ent->second.onboard_transactions;
|
||||
bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc);
|
||||
if(!r || !bvc.m_added_to_main_chain)
|
||||
{
|
||||
|
|
@ -976,7 +987,8 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch
|
|||
for(auto& old_ch_ent : disconnected_chain)
|
||||
{
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc);
|
||||
bvc.m_onboard_transactions.swap(old_ch_ent.onboard_transactions);
|
||||
bool r = handle_alternative_block(old_ch_ent.b, get_block_hash(old_ch_ent.b), bvc);
|
||||
if(!r)
|
||||
{
|
||||
LOG_ERROR("Failed to push ex-main chain blocks to alternative chain ");
|
||||
|
|
@ -1285,6 +1297,35 @@ bool blockchain_storage::create_block_template(block& b,
|
|||
const pos_entry& pe,
|
||||
fill_block_template_func_t custom_fill_block_template_func /* = nullptr */) const
|
||||
{
|
||||
create_block_template_params params = AUTO_VAL_INIT(params);
|
||||
params.miner_address = miner_address;
|
||||
params.stakeholder_address = stakeholder_address;
|
||||
params.ex_nonce = ex_nonce;
|
||||
params.pos = pos;
|
||||
params.pe = pe;
|
||||
params.pcustom_fill_block_template_func = custom_fill_block_template_func;
|
||||
create_block_template_response resp = AUTO_VAL_INIT(resp);
|
||||
bool r = create_block_template(params, resp);
|
||||
b = resp.b;
|
||||
diffic = resp.diffic;
|
||||
height = resp.height;
|
||||
return r;
|
||||
}
|
||||
|
||||
bool blockchain_storage::create_block_template(const create_block_template_params& params, create_block_template_response& resp) const
|
||||
{
|
||||
const account_public_address& miner_address = params.miner_address;
|
||||
const account_public_address& stakeholder_address = params.stakeholder_address;
|
||||
const blobdata& ex_nonce = params.ex_nonce;
|
||||
bool pos = params.pos;
|
||||
const pos_entry& pe = params.pe;
|
||||
fill_block_template_func_t* pcustom_fill_block_template_func = params.pcustom_fill_block_template_func;
|
||||
|
||||
uint64_t& height = resp.height;
|
||||
block& b = resp.b;
|
||||
wide_difficulty_type& diffic = resp.diffic;
|
||||
|
||||
|
||||
size_t median_size;
|
||||
boost::multiprecision::uint128_t already_generated_coins;
|
||||
CRITICAL_REGION_BEGIN(m_read_lock);
|
||||
|
|
@ -1317,13 +1358,13 @@ bool blockchain_storage::create_block_template(block& b,
|
|||
|
||||
CRITICAL_REGION_END();
|
||||
|
||||
size_t txs_size;
|
||||
uint64_t fee;
|
||||
size_t txs_size = 0;
|
||||
uint64_t fee = 0;
|
||||
bool block_filled = false;
|
||||
if (custom_fill_block_template_func == nullptr)
|
||||
block_filled = m_tx_pool.fill_block_template(b, pos, median_size, already_generated_coins, txs_size, fee, height);
|
||||
if (pcustom_fill_block_template_func == nullptr)
|
||||
block_filled = m_tx_pool.fill_block_template(b, pos, median_size, already_generated_coins, txs_size, fee, height, params.explicit_txs);
|
||||
else
|
||||
block_filled = (*custom_fill_block_template_func)(b, pos, median_size, already_generated_coins, txs_size, fee, height);
|
||||
block_filled = (*pcustom_fill_block_template_func)(b, pos, median_size, already_generated_coins, txs_size, fee, height);
|
||||
|
||||
if (!block_filled)
|
||||
return false;
|
||||
|
|
@ -1571,6 +1612,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
|
||||
alt_block_extended_info abei = AUTO_VAL_INIT(abei);
|
||||
abei.bl = b;
|
||||
abei.onboard_transactions.swap(bvc.m_onboard_transactions);
|
||||
abei.timestamp = m_core_runtime_config.get_core_time();
|
||||
abei.height = alt_chain.size() ? it_prev->second.height + 1 : *ptr_main_prev + 1;
|
||||
CHECK_AND_ASSERT_MES_CUSTOM(coinbase_height == abei.height, false, bvc.m_verification_failed = true, "block coinbase height doesn't match with altchain height, declined");
|
||||
|
|
@ -1685,7 +1727,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
alt_chain.push_back(i_res.first);
|
||||
//check if difficulty bigger then in main chain
|
||||
|
||||
bvc.height_difference = get_top_block_height() >= abei.height ? get_top_block_height() - abei.height : 0;
|
||||
bvc.m_height_difference = get_top_block_height() >= abei.height ? get_top_block_height() - abei.height : 0;
|
||||
|
||||
crypto::hash proof = null_hash;
|
||||
std::stringstream ss_pow_pos_info;
|
||||
|
|
@ -1722,7 +1764,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto::
|
|||
bvc.m_verification_failed = true;
|
||||
return r;
|
||||
}
|
||||
bvc.added_to_altchain = true;
|
||||
bvc.m_added_to_altchain = true;
|
||||
|
||||
//protect ourself from altchains container flood
|
||||
if (m_alternative_chains.size() > m_core_runtime_config.max_alt_blocks)
|
||||
|
|
@ -4732,6 +4774,18 @@ wide_difficulty_type blockchain_storage::get_last_alt_x_block_cumulative_precise
|
|||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool get_tx_from_cache(const crypto::hash& tx_id, transactions_map& tx_cache, transaction& tx, size_t& blob_size, uint64_t& fee)
|
||||
{
|
||||
auto it = tx_cache.find(tx_id);
|
||||
if (it == tx_cache.end())
|
||||
return false;
|
||||
|
||||
tx = it->second;
|
||||
blob_size = get_object_blobsize(tx);
|
||||
fee = get_tx_fee(tx);
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc)
|
||||
{
|
||||
TIME_MEASURE_START_PD_MS(block_processing_time_0_ms);
|
||||
|
|
@ -4846,13 +4900,17 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
size_t tx_processed_count = 0;
|
||||
uint64_t fee_summary = 0;
|
||||
uint64_t burned_coins = 0;
|
||||
std::list<crypto::key_image> block_summary_kimages;
|
||||
|
||||
for(const crypto::hash& tx_id : bl.tx_hashes)
|
||||
{
|
||||
transaction tx;
|
||||
size_t blob_size = 0;
|
||||
uint64_t fee = 0;
|
||||
if(!m_tx_pool.take_tx(tx_id, tx, blob_size, fee))
|
||||
|
||||
bool taken_from_cache = get_tx_from_cache(tx_id, bvc.m_onboard_transactions, tx, blob_size, fee);
|
||||
bool taken_from_pool = m_tx_pool.take_tx(tx_id, tx, blob_size, fee);
|
||||
if(!taken_from_cache && !taken_from_pool)
|
||||
{
|
||||
LOG_PRINT_L0("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id);
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
|
|
@ -4861,6 +4919,15 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!validate_tx_semantic(tx, blob_size))
|
||||
{
|
||||
LOG_PRINT_L0("Block with id: " << id << " has at least one transaction with wrong semantic, tx_id: " << tx_id);
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
//add_block_as_invalid(bl, id);
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
append_per_block_increments_for_tx(tx, gindices);
|
||||
|
||||
//If we under checkpoints, ring signatures should be pruned
|
||||
|
|
@ -4875,9 +4942,12 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
{
|
||||
LOG_PRINT_L0("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs.");
|
||||
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
bool add_res = m_tx_pool.add_tx(tx, tvc, true, true);
|
||||
m_tx_pool.add_transaction_to_black_list(tx);
|
||||
CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool");
|
||||
if (taken_from_pool)
|
||||
{
|
||||
bool add_res = m_tx_pool.add_tx(tx, tvc, true, true);
|
||||
m_tx_pool.add_transaction_to_black_list(tx);
|
||||
CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool");
|
||||
}
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
add_block_as_invalid(bl, id);
|
||||
LOG_PRINT_L0("Block with id " << id << " added as invalid because of wrong inputs in transactions");
|
||||
|
|
@ -4895,10 +4965,13 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
if(!add_transaction_from_block(tx, tx_id, id, current_bc_size, actual_timestamp))
|
||||
{
|
||||
LOG_PRINT_L0("Block with id: " << id << " failed to add transaction to blockchain storage");
|
||||
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
bool add_res = m_tx_pool.add_tx(tx, tvc, true, true);
|
||||
m_tx_pool.add_transaction_to_black_list(tx);
|
||||
CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool");
|
||||
if (taken_from_pool)
|
||||
{
|
||||
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
bool add_res = m_tx_pool.add_tx(tx, tvc, true, true);
|
||||
m_tx_pool.add_transaction_to_black_list(tx);
|
||||
CHECK_AND_ASSERT_MES_NO_RET(add_res, "handle_block_to_main_chain: failed to add transaction back to transaction pool");
|
||||
}
|
||||
purge_block_data_from_blockchain(bl, tx_processed_count);
|
||||
bvc.m_verification_failed = true;
|
||||
return false;
|
||||
|
|
@ -4911,6 +4984,8 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
++tx_processed_count;
|
||||
if (fee)
|
||||
block_fees.push_back(fee);
|
||||
|
||||
read_keyimages_from_tx(tx, block_summary_kimages);
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD(all_txs_insert_time_5);
|
||||
|
||||
|
|
@ -4945,8 +5020,6 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
if (is_pos_bl)
|
||||
bei.stake_hash = proof_hash;
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//old style cumulative difficulty collecting
|
||||
|
|
@ -5084,17 +5157,17 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
<< "/" << etc_stuff_6
|
||||
<< "))");
|
||||
|
||||
on_block_added(bei, id);
|
||||
on_block_added(bei, id, block_summary_kimages);
|
||||
|
||||
bvc.m_added_to_main_chain = true;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
void blockchain_storage::on_block_added(const block_extended_info& bei, const crypto::hash& id)
|
||||
void blockchain_storage::on_block_added(const block_extended_info& bei, const crypto::hash& id, const std::list<crypto::key_image>& bsk)
|
||||
{
|
||||
update_next_comulative_size_limit();
|
||||
m_timestamps_median_cache.clear();
|
||||
m_tx_pool.on_blockchain_inc(bei.height, id);
|
||||
m_tx_pool.on_blockchain_inc(bei.height, id, bsk);
|
||||
|
||||
update_targetdata_cache_on_block_added(bei);
|
||||
|
||||
|
|
@ -5283,7 +5356,8 @@ bool blockchain_storage::truncate_blockchain(uint64_t to_height)
|
|||
uint64_t inital_height = get_current_blockchain_size();
|
||||
while (get_current_blockchain_size() > to_height)
|
||||
{
|
||||
pop_block_from_blockchain();
|
||||
transactions_map ot;
|
||||
pop_block_from_blockchain(ot);
|
||||
}
|
||||
CRITICAL_REGION_LOCAL(m_alternative_chains_lock);
|
||||
m_alternative_chains.clear();
|
||||
|
|
@ -6003,8 +6077,12 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
|
|||
for (auto tx_id : b.tx_hashes)
|
||||
{
|
||||
std::shared_ptr<transaction> tx_ptr;
|
||||
CHECK_AND_ASSERT_MES(get_transaction_from_pool_or_db(tx_id, tx_ptr, split_height), false, "failed to get alt block tx " << tx_id << " with split_height == " << split_height);
|
||||
transaction& tx = *tx_ptr;
|
||||
auto it = abei.onboard_transactions.find(tx_id);
|
||||
if (it == abei.onboard_transactions.end())
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(get_transaction_from_pool_or_db(tx_id, tx_ptr, split_height), false, "failed to get alt block tx " << tx_id << " with split_height == " << split_height);
|
||||
}
|
||||
const transaction& tx = it == abei.onboard_transactions.end() ? *tx_ptr : it->second;
|
||||
CHECK_AND_ASSERT_MES(tx.signatures.size() == tx.vin.size(), false, "invalid tx: tx.signatures.size() == " << tx.signatures.size() << ", tx.vin.size() == " << tx.vin.size());
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ namespace currency
|
|||
|
||||
//date added to alt chain storage
|
||||
uint64_t timestamp;
|
||||
|
||||
//transactions associated with the block
|
||||
transactions_map onboard_transactions;
|
||||
};
|
||||
typedef std::unordered_map<crypto::hash, alt_block_extended_info> alt_chain_container;
|
||||
//typedef std::list<alt_chain_container::iterator> alt_chain_type;
|
||||
|
|
@ -240,9 +243,10 @@ namespace currency
|
|||
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_cached_next_difficulty(bool pos) const;
|
||||
|
||||
typedef bool fill_block_template_func_t(block &bl, bool pos, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height);
|
||||
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func = nullptr) const;
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const;
|
||||
bool create_block_template(const create_block_template_params& params, create_block_template_response& resp) const;
|
||||
|
||||
bool have_block(const crypto::hash& id) const;
|
||||
size_t get_total_transactions()const;
|
||||
|
|
@ -542,10 +546,10 @@ namespace currency
|
|||
bool switch_to_alternative_blockchain(alt_chain_type& alt_chain);
|
||||
void purge_alt_block_txs_hashs(const block& b);
|
||||
void add_alt_block_txs_hashs(const block& b);
|
||||
bool pop_block_from_blockchain();
|
||||
bool pop_block_from_blockchain(transactions_map& onboard_transactions);
|
||||
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count);
|
||||
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count, uint64_t& fee);
|
||||
bool purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee);
|
||||
bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count, uint64_t& fee, transactions_map& onboard_transactions);
|
||||
bool purge_transaction_from_blockchain(const crypto::hash& tx_id, uint64_t& fee, transaction& tx);
|
||||
bool purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check);
|
||||
wide_difficulty_type get_next_difficulty_for_alternative_chain(const alt_chain_type& alt_chain, block_extended_info& bei, bool pos) const;
|
||||
bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc);
|
||||
|
|
@ -564,7 +568,7 @@ namespace currency
|
|||
bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr<transaction>& tx_ptr, uint64_t min_allowed_block_height = 0) const;
|
||||
void get_last_n_x_blocks(uint64_t n, bool pos_blocks, std::list<std::shared_ptr<const block_extended_info>>& blocks) const;
|
||||
bool prevalidate_miner_transaction(const block& b, uint64_t height, bool pos)const;
|
||||
bool rollback_blockchain_switching(std::list<block>& original_chain, size_t rollback_height);
|
||||
bool rollback_blockchain_switching(std::list<block_ws_txs>& original_chain, size_t rollback_height);
|
||||
bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp);
|
||||
bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes);
|
||||
bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id);
|
||||
|
|
@ -577,7 +581,7 @@ namespace currency
|
|||
bool check_block_timestamp(std::vector<uint64_t> timestamps, const block& b)const;
|
||||
std::vector<uint64_t> get_last_n_blocks_timestamps(size_t n)const;
|
||||
const std::vector<txin_etc_details_v>& get_txin_etc_options(const txin_v& in)const;
|
||||
void on_block_added(const block_extended_info& bei, const crypto::hash& id);
|
||||
void on_block_added(const block_extended_info& bei, const crypto::hash& id, const std::list<crypto::key_image>& bsk);
|
||||
void on_block_removed(const block_extended_info& bei);
|
||||
void update_targetdata_cache_on_block_added(const block_extended_info& bei);
|
||||
void update_targetdata_cache_on_block_removed(const block_extended_info& bei);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
|
||||
|
|
@ -17,7 +18,7 @@
|
|||
|
||||
#include "currency_basic.h"
|
||||
#include "difficulty.h"
|
||||
|
||||
#include "currency_protocol/blobdatatype.h"
|
||||
namespace currency
|
||||
{
|
||||
|
||||
|
|
@ -125,6 +126,32 @@ namespace currency
|
|||
}
|
||||
};
|
||||
|
||||
typedef bool fill_block_template_func_t(block &bl, bool pos, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height);
|
||||
|
||||
struct create_block_template_params
|
||||
{
|
||||
account_public_address miner_address;
|
||||
account_public_address stakeholder_address;
|
||||
blobdata ex_nonce;
|
||||
bool pos = false;
|
||||
pos_entry pe;
|
||||
std::list<transaction> explicit_txs;
|
||||
fill_block_template_func_t *pcustom_fill_block_template_func;
|
||||
};
|
||||
|
||||
struct create_block_template_response
|
||||
{
|
||||
block b;
|
||||
wide_difficulty_type diffic;
|
||||
uint64_t height;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<crypto::hash, transaction> transactions_map;
|
||||
|
||||
struct block_ws_txs
|
||||
{
|
||||
block b;
|
||||
transactions_map onboard_transactions;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ using namespace epee;
|
|||
#include "currency_format_utils.h"
|
||||
#include "misc_language.h"
|
||||
#include "string_coding.h"
|
||||
#include "tx_semantic_validation.h"
|
||||
|
||||
#define MINIMUM_REQUIRED_FREE_SPACE_BYTES (1024 * 1024 * 100)
|
||||
|
||||
|
|
@ -185,13 +186,15 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool kept_by_block)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!kept_by_block, false, "Transaction associated with block came throw handle_incoming_tx!(not allowed anymore)");
|
||||
|
||||
tvc = boost::value_initialized<tx_verification_context>();
|
||||
//want to process all transactions sequentially
|
||||
TIME_MEASURE_START_MS(wait_lock_time);
|
||||
CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
|
||||
TIME_MEASURE_FINISH_MS(wait_lock_time);
|
||||
|
||||
if(tx_blob.size() > get_max_tx_size())
|
||||
if(tx_blob.size() > CURRENCY_MAX_TRANSACTION_BLOB_SIZE)
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, too big size " << tx_blob.size() << ", rejected");
|
||||
tvc.m_verification_failed = true;
|
||||
|
|
@ -210,19 +213,10 @@ namespace currency
|
|||
TIME_MEASURE_FINISH_MS(parse_tx_time);
|
||||
|
||||
|
||||
TIME_MEASURE_START_MS(check_tx_syntax_time);
|
||||
if(!check_tx_syntax(tx))
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " syntax, rejected");
|
||||
tvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
TIME_MEASURE_FINISH_MS(check_tx_syntax_time);
|
||||
|
||||
TIME_MEASURE_START_MS(check_tx_semantic_time);
|
||||
if(!check_tx_semantic(tx, kept_by_block))
|
||||
if(!validate_tx_semantic(tx, tx_blob.size()))
|
||||
{
|
||||
LOG_PRINT_L0("WRONG TRANSACTION BLOB, Failed to check tx " << tx_hash << " semantic, rejected");
|
||||
LOG_PRINT_L0("WRONG TRANSACTION SEMANTICS, Failed to check tx " << tx_hash << " semantic, rejected");
|
||||
tvc.m_verification_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -243,7 +237,6 @@ namespace currency
|
|||
}
|
||||
LOG_PRINT_L2("[CORE HANDLE_INCOMING_TX]: timing " << wait_lock_time
|
||||
<< "/" << parse_tx_time
|
||||
<< "/" << check_tx_syntax_time
|
||||
<< "/" << check_tx_semantic_time
|
||||
<< "/" << add_new_tx_time);
|
||||
return r;
|
||||
|
|
@ -296,88 +289,9 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_semantic(const transaction& tx, bool kept_by_block)
|
||||
{
|
||||
if(!tx.vin.size())
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_inputs_types_supported(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("unsupported input types for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_outs_valid(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_money_overflow(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx has money overflow, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t amount_in = 0;
|
||||
get_inputs_money_amount(tx, amount_in);
|
||||
uint64_t amount_out = get_outs_money_amount(tx);
|
||||
|
||||
if(amount_in < amount_out)
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!kept_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_comulative_blocksize_limit() - CURRENCY_COINBASE_BLOB_RESERVED_SIZE)
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx has too big size " << get_object_blobsize(tx) << ", expected no bigger than " << m_blockchain_storage.get_current_comulative_blocksize_limit() - CURRENCY_COINBASE_BLOB_RESERVED_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if tx use different key images
|
||||
if(!check_tx_inputs_keyimages_diff(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx inputs have the same key images");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_tx_extra(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx has wrong extra, rejected");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_extra(const transaction& tx)
|
||||
{
|
||||
tx_extra_info ei = AUTO_VAL_INIT(ei);
|
||||
bool r = parse_and_validate_tx_extra(tx, ei);
|
||||
if(!r)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_inputs_keyimages_diff(const transaction& tx)
|
||||
{
|
||||
std::unordered_set<crypto::key_image> ki;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if (!ki.insert(tokey_in.k_image).second)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_tx(const transaction& tx, tx_verification_context& tvc, bool kept_by_block)
|
||||
{
|
||||
|
|
@ -419,6 +333,11 @@ namespace currency
|
|||
return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(const create_block_template_params& params, create_block_template_response& resp)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(params, resp);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
|
||||
{
|
||||
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, resp);
|
||||
|
|
@ -589,7 +508,6 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate)
|
||||
{
|
||||
bvc = AUTO_VAL_INIT_T(block_verification_context);
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
if (!parse_block(block_blob, b, bvc))
|
||||
{
|
||||
|
|
@ -627,11 +545,6 @@ namespace currency
|
|||
{
|
||||
return parse_and_validate_tx_from_blob(blob, tx, tx_hash);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::check_tx_syntax(const transaction& tx)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_pool_transactions(std::list<transaction>& txs)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ namespace currency
|
|||
|
||||
//-------------------- i_miner_handler -----------------------
|
||||
virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr);
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry());
|
||||
virtual bool get_block_template(const create_block_template_params& params, create_block_template_response& resp);
|
||||
bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry());
|
||||
|
||||
miner& get_miner(){ return m_miner; }
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
|
|
@ -118,12 +119,6 @@ namespace currency
|
|||
bool add_new_block(const block& b, block_verification_context& bvc);
|
||||
bool load_state_data();
|
||||
bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob);
|
||||
bool check_tx_extra(const transaction& tx);
|
||||
|
||||
bool check_tx_syntax(const transaction& tx);
|
||||
//check correct values, amounts and all lightweight checks not related with database
|
||||
bool check_tx_semantic(const transaction& tx, bool kept_by_block);
|
||||
//check if tx already in memory pool or in main blockchain
|
||||
|
||||
bool is_key_image_spent(const crypto::key_image& key_im);
|
||||
|
||||
|
|
@ -132,7 +127,6 @@ namespace currency
|
|||
bool update_miner_block_template();
|
||||
bool handle_command_line(const boost::program_options::variables_map& vm);
|
||||
bool on_update_blocktemplate_interval();
|
||||
bool check_tx_inputs_keyimages_diff(const transaction& tx);
|
||||
|
||||
void notify_blockchain_update_listeners();
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ namespace currency
|
|||
bool pos,
|
||||
const pos_entry& pe)
|
||||
{
|
||||
uint64_t block_reward;
|
||||
uint64_t block_reward = 0;
|
||||
if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward, height))
|
||||
{
|
||||
LOG_ERROR("Block is too big");
|
||||
|
|
@ -857,14 +857,6 @@ namespace currency
|
|||
tx.extra.push_back(chs);
|
||||
else
|
||||
tx.attachment.push_back(chs);
|
||||
|
||||
LOG_PRINT_GREEN("ENCRYPTING ATTACHMENTS ON KEY: " << epee::string_tools::pod_to_hex(derivation)
|
||||
<< " destination addr: " << currency::get_account_address_as_str(destination_addr)
|
||||
<< " tx_random_key.sec" << tx_random_key.sec
|
||||
<< " tx_random_key.pub" << tx_random_key.pub
|
||||
<< " sender address: " << currency::get_account_address_as_str(sender_keys.m_account_address)
|
||||
, LOG_LEVEL_0);
|
||||
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
@ -981,6 +973,8 @@ namespace currency
|
|||
{
|
||||
CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "Too many outs (" << destinations.size() << ")! Tx can't be constructed.");
|
||||
|
||||
bool watch_only_mode = sender_account_keys.m_spend_secret_key == null_skey;
|
||||
|
||||
bool append_mode = false;
|
||||
if (flags&TX_FLAG_SIGNATURE_MODE_SEPARATE && tx.vin.size())
|
||||
append_mode = true;
|
||||
|
|
@ -1196,10 +1190,12 @@ namespace currency
|
|||
}
|
||||
sigs.resize(src_entr.outputs.size());
|
||||
|
||||
crypto::generate_ring_signature(tx_hash_for_signature, boost::get<txin_to_key>(tx.vin[input_index]).k_image, keys_ptrs, in_contexts[in_context_index].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
if (!watch_only_mode)
|
||||
crypto::generate_ring_signature(tx_hash_for_signature, boost::get<txin_to_key>(tx.vin[input_index]).k_image, keys_ptrs, in_contexts[in_context_index].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
|
||||
ss_ring_s << "signatures:" << ENDL;
|
||||
std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL; });
|
||||
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[in_context_index].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
|
||||
std::for_each(sigs.begin(), sigs.end(), [&ss_ring_s](const crypto::signature& s) { ss_ring_s << s << ENDL; });
|
||||
ss_ring_s << "prefix_hash: " << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[in_context_index].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1525,14 +1521,16 @@ namespace currency
|
|||
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index)
|
||||
{
|
||||
crypto::public_key pk;
|
||||
derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
|
||||
if (!derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk))
|
||||
return false;
|
||||
return pk == out_key.key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index)
|
||||
{
|
||||
crypto::public_key pk;
|
||||
derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
|
||||
if (!derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk))
|
||||
return false;
|
||||
auto it = std::find(out_multisig.keys.begin(), out_multisig.keys.end(), pk);
|
||||
if (out_multisig.keys.end() == it)
|
||||
return false;
|
||||
|
|
@ -1593,7 +1591,8 @@ namespace currency
|
|||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation)
|
||||
{
|
||||
money_transfered = 0;
|
||||
generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
|
||||
bool r = generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "unable to generate derivation from tx_pub = " << tx_pub_key << " * view_sec, invalid tx_pub?");
|
||||
|
||||
if (is_coinbase(tx) && get_block_height(tx) == 0 && tx_pub_key == ggenesis_tx_pub_key)
|
||||
{
|
||||
|
|
@ -2431,11 +2430,6 @@ namespace currency
|
|||
return CURRENCY_MAX_BLOCK_SIZE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t get_max_tx_size()
|
||||
{
|
||||
return CURRENCY_MAX_TRANSACTION_BLOB_SIZE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
uint64_t get_base_block_reward(bool is_pos, const boost::multiprecision::uint128_t& already_generated_coins, uint64_t height)
|
||||
{
|
||||
if (!height)
|
||||
|
|
@ -2480,7 +2474,7 @@ namespace currency
|
|||
div128_32(product_hi, product_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
|
||||
div128_32(reward_hi, reward_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
|
||||
CHECK_AND_ASSERT_MES(0 == reward_hi, false, "0 == reward_hi");
|
||||
CHECK_AND_ASSERT_MES(reward_lo < base_reward, false, "reward_lo < base_reward, reward: " << reward << ", base_reward: " << base_reward << ", current_block_size: " << current_block_size << ", median_size: " << median_size);
|
||||
CHECK_AND_ASSERT_MES(reward_lo < base_reward, false, "reward_lo < base_reward, reward_lo: " << reward_lo << ", base_reward: " << base_reward << ", current_block_size: " << current_block_size << ", median_size: " << median_size);
|
||||
|
||||
reward = reward_lo;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -193,6 +193,16 @@ namespace currency
|
|||
return get_object_blobsize(t, tx_blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_objects_blobsize(const std::list<transaction>& ls)
|
||||
{
|
||||
size_t total = 0;
|
||||
for (const auto& tx : ls)
|
||||
{
|
||||
total += get_object_blobsize(tx);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size)
|
||||
{
|
||||
size_t tx_blob_size = prefix_blob_size;
|
||||
|
|
@ -246,5 +256,20 @@ namespace currency
|
|||
{
|
||||
return t_serializable_object_to_blob(tx, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool read_keyimages_from_tx(const transaction& tx, std::list<crypto::key_image>& kil)
|
||||
{
|
||||
std::unordered_set<crypto::key_image> ki;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if (!ki.insert(tokey_in.k_image).second)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -92,7 +92,7 @@ namespace currency
|
|||
inline void set_tx_flags(transaction& tx, uint64_t v) { set_tx_x_detail<etc_tx_details_flags>(tx, v); }
|
||||
inline void set_tx_expiration_time(transaction& tx, uint64_t v) { set_tx_x_detail<etc_tx_details_expiration_time>(tx, v); }
|
||||
account_public_address get_crypt_address_from_destinations(const account_keys& sender_account_keys, const std::vector<tx_destination_entry>& destinations);
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median);
|
||||
uint64_t get_burned_amount(const transaction& tx);
|
||||
|
|
@ -104,7 +104,11 @@ namespace currency
|
|||
bool get_transaction_hash(const transaction& t, crypto::hash& res);
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, uint64_t& blob_size);
|
||||
size_t get_object_blobsize(const transaction& t);
|
||||
size_t get_objects_blobsize(const std::list<transaction>& ls);
|
||||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size);
|
||||
blobdata tx_to_blob(const transaction& b);
|
||||
bool tx_to_blob(const transaction& b, blobdata& b_blob);
|
||||
bool read_keyimages_from_tx(const transaction& tx, std::list<crypto::key_image>& kil);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,13 +56,16 @@ namespace currency
|
|||
m_current_hash_rate(0),
|
||||
m_last_hr_merge_time(0),
|
||||
m_hashes(0),
|
||||
m_config(AUTO_VAL_INIT(m_config))
|
||||
m_config(AUTO_VAL_INIT(m_config)),
|
||||
m_mine_address{}
|
||||
{
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
miner::~miner()
|
||||
{
|
||||
TRY_ENTRY();
|
||||
stop();
|
||||
CATCH_ENTRY_NO_RETURN();
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
bool miner::set_block_template(const block& bl, const wide_difficulty_type& di, uint64_t height)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ namespace currency
|
|||
struct i_miner_handler
|
||||
{
|
||||
virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr) = 0;
|
||||
virtual bool get_block_template(const create_block_template_params& params, create_block_template_response& resp) = 0;
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()) = 0;
|
||||
protected:
|
||||
~i_miner_handler(){};
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ namespace currency
|
|||
m_db_transactions(m_db),
|
||||
m_db_black_tx_list(m_db),
|
||||
m_db_solo_options(m_db),
|
||||
m_db_key_images_set(m_db),
|
||||
// m_db_key_images_set(m_db),
|
||||
m_db_alias_names(m_db),
|
||||
m_db_alias_addresses(m_db),
|
||||
m_db_storage_major_compatibility_version(TRANSACTION_POOL_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION, m_db_solo_options)
|
||||
|
|
@ -255,7 +255,7 @@ namespace currency
|
|||
td.receive_time = get_core_time();
|
||||
|
||||
m_db_transactions.set(id, td);
|
||||
on_tx_add(tx, kept_by_block);
|
||||
on_tx_add(id, tx, kept_by_block);
|
||||
|
||||
TIME_MEASURE_FINISH_PD(update_db_time);
|
||||
return true;
|
||||
|
|
@ -385,7 +385,7 @@ namespace currency
|
|||
blob_size = txe_tr->blob_size;
|
||||
fee = txe_tr->fee;
|
||||
m_db_transactions.erase(id);
|
||||
on_tx_remove(tx, txe_tr->kept_by_block);
|
||||
on_tx_remove(id, tx, txe_tr->kept_by_block);
|
||||
set_taken(id);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -472,7 +472,7 @@ namespace currency
|
|||
for (auto& e : to_delete)
|
||||
{
|
||||
m_db_transactions.erase(e.hash);
|
||||
on_tx_remove(e.tx, e.kept_by_block);
|
||||
on_tx_remove(e.hash, e.tx, e.kept_by_block);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -613,8 +613,10 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id)
|
||||
bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id, const std::list<crypto::key_image>& bsk)
|
||||
{
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
|
|
@ -694,36 +696,33 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::insert_key_images(const transaction& tx, bool kept_by_block)
|
||||
bool tx_memory_pool::insert_key_images(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_key_images_lock);
|
||||
for(const auto& in : tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail
|
||||
uint64_t count = 0;
|
||||
auto ki_entry_ptr = m_db_key_images_set.get(tokey_in.k_image);
|
||||
if (ki_entry_ptr.get())
|
||||
count = *ki_entry_ptr;
|
||||
uint64_t count_before = count;
|
||||
++count;
|
||||
m_db_key_images_set.set(tokey_in.k_image, count);
|
||||
LOG_PRINT_L2("tx pool: key image added: " << tokey_in.k_image << ", from tx " << get_transaction_hash(tx) << ", counter: " << count_before << " -> " << count);
|
||||
const txin_to_key& tokey_in = boost::get<txin_to_key>(in);
|
||||
auto& id_set = m_key_images[tokey_in.k_image];
|
||||
size_t sz_before = id_set.size();
|
||||
id_set.insert(tx_id);
|
||||
LOG_PRINT_L2("tx pool: key image added: " << tokey_in.k_image << ", from tx " << tx_id << ", counter: " << sz_before << " -> " << id_set.size());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::on_tx_add(const transaction& tx, bool kept_by_block)
|
||||
bool tx_memory_pool::on_tx_add(crypto::hash tx_id, const transaction& tx, bool kept_by_block)
|
||||
{
|
||||
insert_key_images(tx, kept_by_block);
|
||||
insert_key_images(tx_id, tx, kept_by_block);
|
||||
insert_alias_info(tx);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::on_tx_remove(const transaction& tx, bool kept_by_block)
|
||||
bool tx_memory_pool::on_tx_remove(const crypto::hash &id, const transaction& tx, bool kept_by_block)
|
||||
{
|
||||
remove_key_images(tx, kept_by_block);
|
||||
remove_key_images(id, tx, kept_by_block);
|
||||
remove_alias_info(tx);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -757,34 +756,33 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::remove_key_images(const transaction& tx, bool kept_by_block)
|
||||
bool tx_memory_pool::remove_key_images(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_key_images_lock);
|
||||
for(const auto& in : tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail
|
||||
uint64_t count = 0;
|
||||
auto ki_entry_ptr = m_db_key_images_set.get(tokey_in.k_image);
|
||||
if (!ki_entry_ptr.get() || *ki_entry_ptr == 0)
|
||||
{
|
||||
LOG_ERROR("INTERNAL_ERROR: for tx " << get_transaction_hash(tx) << " key image " << tokey_in.k_image << " not found");
|
||||
continue;
|
||||
}
|
||||
count = *ki_entry_ptr;
|
||||
uint64_t count_before = count;
|
||||
--count;
|
||||
if (count)
|
||||
m_db_key_images_set.set(tokey_in.k_image, count);
|
||||
else
|
||||
m_db_key_images_set.erase(tokey_in.k_image);
|
||||
LOG_PRINT_L2("tx pool: key image removed: " << tokey_in.k_image << ", from tx " << get_transaction_hash(tx) << ", counter: " << count_before << " -> " << count);
|
||||
{
|
||||
const txin_to_key& tokey_in = boost::get<txin_to_key>(in);
|
||||
|
||||
auto it_map = epee::misc_utils::it_get_or_insert_value_initialized(m_key_images, tokey_in.k_image);
|
||||
auto& id_set = it_map->second;
|
||||
size_t count_before = id_set.size();
|
||||
auto it_set = id_set.find(tx_id);
|
||||
if(it_set != id_set.end())
|
||||
id_set.erase(it_set);
|
||||
|
||||
size_t count_after = id_set.size();
|
||||
if (id_set.size() == 0)
|
||||
m_key_images.erase(it_map);
|
||||
|
||||
LOG_PRINT_L2("tx pool: key image removed: " << tokey_in.k_image << ", from tx " << tx_id << ", counter: " << count_before << " -> " << count_after);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::get_key_images_from_tx_pool(std::unordered_set<crypto::key_image>& key_images) const
|
||||
bool tx_memory_pool::get_key_images_from_tx_pool(key_image_cache& key_images) const
|
||||
{
|
||||
|
||||
m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry)
|
||||
|
|
@ -793,7 +791,7 @@ namespace currency
|
|||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
{
|
||||
key_images.insert(boost::get<txin_to_key>(in).k_image);
|
||||
key_images[boost::get<txin_to_key>(in).k_image].insert(h);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -804,9 +802,9 @@ namespace currency
|
|||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im)const
|
||||
{
|
||||
|
||||
auto ptr = m_db_key_images_set.find(key_im);
|
||||
if (ptr)
|
||||
CRITICAL_REGION_LOCAL(m_key_images_lock);
|
||||
auto it = m_key_images.find(key_im);
|
||||
if (it != m_key_images.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -826,9 +824,9 @@ namespace currency
|
|||
|
||||
m_db.begin_transaction();
|
||||
m_db_transactions.clear();
|
||||
m_db_key_images_set.clear();
|
||||
m_db.commit_transaction();
|
||||
// should m_db_black_tx_list be cleared here?
|
||||
CIRITCAL_OPERATION(m_key_images,clear());
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::clear()
|
||||
|
|
@ -836,8 +834,8 @@ namespace currency
|
|||
m_db.begin_transaction();
|
||||
m_db_transactions.clear();
|
||||
m_db_black_tx_list.clear();
|
||||
m_db_key_images_set.clear();
|
||||
m_db.commit_transaction();
|
||||
CIRITCAL_OPERATION(m_key_images,clear());
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::is_transaction_ready_to_go(tx_details& txd, const crypto::hash& id)const
|
||||
|
|
@ -987,7 +985,9 @@ namespace currency
|
|||
const boost::multiprecision::uint128_t& already_generated_coins,
|
||||
size_t &total_size,
|
||||
uint64_t &fee,
|
||||
uint64_t height)
|
||||
uint64_t height,
|
||||
const std::list<transaction>& explicit_txs
|
||||
)
|
||||
{
|
||||
LOCAL_READONLY_TRANSACTION();
|
||||
//typedef transactions_container::value_type txv;
|
||||
|
|
@ -998,8 +998,8 @@ namespace currency
|
|||
txs_v.reserve(m_db_transactions.size());
|
||||
std::vector<txv*> txs;
|
||||
|
||||
//std::transform(m_transactions.begin(), m_transactions.end(), txs.begin(), [](txv &a) -> txv * { return &a; });
|
||||
//keep getting it as a values cz db items cache will keep it as unserialied object stored by shared ptrs
|
||||
|
||||
//keep getting it as a values cz db items cache will keep it as unserialised object stored by shared ptrs
|
||||
m_db_transactions.enumerate_keys([&](uint64_t i, crypto::hash& k){txs_v.resize(i + 1); txs_v[i].first = k; return true;});
|
||||
txs.resize(txs_v.size(), nullptr);
|
||||
|
||||
|
|
@ -1024,7 +1024,9 @@ namespace currency
|
|||
return a_ > b_;
|
||||
});
|
||||
|
||||
size_t current_size = 0;
|
||||
|
||||
size_t explicit_total_size = get_objects_blobsize(explicit_txs);
|
||||
size_t current_size = explicit_total_size;
|
||||
uint64_t current_fee = 0;
|
||||
uint64_t best_money;
|
||||
if (!get_block_reward(pos, median_size, CURRENCY_COINBASE_BLOB_RESERVED_SIZE, already_generated_coins, best_money, height)) {
|
||||
|
|
@ -1133,6 +1135,12 @@ namespace currency
|
|||
}
|
||||
}
|
||||
}
|
||||
// add explicit transactions
|
||||
for (const auto& tx : explicit_txs)
|
||||
{
|
||||
fee += get_tx_fee(tx);
|
||||
bl.tx_hashes.push_back(get_transaction_hash(tx));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
|
|
@ -1184,8 +1192,8 @@ namespace currency
|
|||
|
||||
res = m_db_transactions.init(TRANSACTION_POOL_CONTAINER_TRANSACTIONS);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Unable to init db container");
|
||||
res = m_db_key_images_set.init(TRANSACTION_POOL_CONTAINER_KEY_IMAGES);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Unable to init db container");
|
||||
// res = m_db_key_images_set.init(TRANSACTION_POOL_CONTAINER_KEY_IMAGES);
|
||||
// CHECK_AND_ASSERT_MES(res, false, "Unable to init db container");
|
||||
res = m_db_black_tx_list.init(TRANSACTION_POOL_CONTAINER_BLACK_TX_LIST);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Unable to init db container");
|
||||
res = m_db_alias_names.init(TRANSACTION_POOL_CONTAINER_ALIAS_NAMES);
|
||||
|
|
@ -1211,7 +1219,7 @@ namespace currency
|
|||
{
|
||||
LOG_PRINT_L1("DB at " << db_folder_path << " is about to be deleted and re-created...");
|
||||
m_db_transactions.deinit();
|
||||
m_db_key_images_set.deinit();
|
||||
// m_db_key_images_set.deinit();
|
||||
m_db_black_tx_list.deinit();
|
||||
m_db_alias_names.deinit();
|
||||
m_db_alias_addresses.deinit();
|
||||
|
|
@ -1243,9 +1251,17 @@ namespace currency
|
|||
});
|
||||
LOG_PRINT_L2(ss.str());
|
||||
}
|
||||
|
||||
load_keyimages_cache();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::load_keyimages_cache()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_key_images_lock);
|
||||
return get_key_images_from_tx_pool(m_key_images);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::deinit()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ namespace currency
|
|||
epee::math_helper::average<uint64_t, 5> db_commit_time;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<crypto::key_image, std::set<crypto::hash>> key_image_cache;
|
||||
|
||||
tx_memory_pool(blockchain_storage& bchs, i_currency_protocol* pprotocol);
|
||||
bool add_tx(const transaction &tx, const crypto::hash &id, uint64_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool from_core = false);
|
||||
|
|
@ -99,7 +100,7 @@ namespace currency
|
|||
|
||||
bool check_tx_multisig_ins_and_outs(const transaction& tx, bool check_against_pool_txs)const;
|
||||
|
||||
bool on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id);
|
||||
bool on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id, const std::list<crypto::key_image>& bsk);
|
||||
bool on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id);
|
||||
bool on_finalize_db_transaction();
|
||||
bool add_transaction_to_black_list(const transaction& tx);
|
||||
|
|
@ -117,7 +118,7 @@ namespace currency
|
|||
// load/store operations
|
||||
bool init(const std::string& config_folder, const boost::program_options::variables_map& vm);
|
||||
bool deinit();
|
||||
bool fill_block_template(block &bl, bool pos, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height);
|
||||
bool fill_block_template(block &bl, bool pos, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height, const std::list<transaction>& explicit_txs);
|
||||
bool get_transactions(std::list<transaction>& txs) const;
|
||||
bool get_all_transactions_details(std::list<tx_rpc_extended_info>& txs)const;
|
||||
bool get_all_transactions_brief_details(std::list<tx_rpc_brief_info>& txs)const;
|
||||
|
|
@ -139,10 +140,10 @@ namespace currency
|
|||
bool remove_stuck_transactions(); // made public to be called from coretests
|
||||
|
||||
private:
|
||||
bool on_tx_add(const transaction& tx, bool kept_by_block);
|
||||
bool on_tx_remove(const transaction& tx, bool kept_by_block);
|
||||
bool insert_key_images(const transaction& tx, bool kept_by_block);
|
||||
bool remove_key_images(const transaction& tx, bool kept_by_block);
|
||||
bool on_tx_add(crypto::hash tx_id, const transaction& tx, bool kept_by_block);
|
||||
bool on_tx_remove(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block);
|
||||
bool insert_key_images(const crypto::hash& tx_id, const transaction& tx, bool kept_by_block);
|
||||
bool remove_key_images(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block);
|
||||
bool insert_alias_info(const transaction& tx);
|
||||
bool remove_alias_info(const transaction& tx);
|
||||
|
||||
|
|
@ -150,16 +151,15 @@ namespace currency
|
|||
void store_db_solo_options_values();
|
||||
bool is_transaction_ready_to_go(tx_details& txd, const crypto::hash& id)const;
|
||||
bool validate_alias_info(const transaction& tx, bool is_in_block)const;
|
||||
bool get_key_images_from_tx_pool(std::unordered_set<crypto::key_image>& key_images)const;
|
||||
//bool push_alias_info(const transaction& tx);
|
||||
//bool pop_alias_info(const transaction& tx);
|
||||
bool get_key_images_from_tx_pool(key_image_cache& key_images) const;
|
||||
bool check_is_taken(const crypto::hash& id) const;
|
||||
void set_taken(const crypto::hash& id);
|
||||
void reset_all_taken();
|
||||
bool load_keyimages_cache();
|
||||
|
||||
typedef tools::db::cached_key_value_accessor<crypto::hash, tx_details, true, false> transactions_container;
|
||||
typedef tools::db::cached_key_value_accessor<crypto::hash, bool, false, false> hash_container;
|
||||
typedef tools::db::cached_key_value_accessor<crypto::key_image, uint64_t, false, false> key_images_container;
|
||||
//typedef tools::db::cached_key_value_accessor<crypto::key_image, uint64_t, false, false> key_images_container;
|
||||
typedef tools::db::cached_key_value_accessor<uint64_t, uint64_t, false, true> solo_options_container;
|
||||
typedef tools::db::cached_key_value_accessor<std::string, bool, false, false> aliases_container;
|
||||
typedef tools::db::cached_key_value_accessor<account_public_address, bool, false, false> address_to_aliases_container;
|
||||
|
|
@ -172,7 +172,7 @@ namespace currency
|
|||
|
||||
transactions_container m_db_transactions;
|
||||
hash_container m_db_black_tx_list;
|
||||
key_images_container m_db_key_images_set;
|
||||
//key_images_container m_db_key_images_set;
|
||||
aliases_container m_db_alias_names;
|
||||
address_to_aliases_container m_db_alias_addresses;
|
||||
solo_options_container m_db_solo_options;
|
||||
|
|
@ -189,6 +189,9 @@ namespace currency
|
|||
//in memory containers
|
||||
mutable epee::critical_section m_taken_txs_lock;
|
||||
std::unordered_set<crypto::hash> m_taken_txs;
|
||||
|
||||
mutable epee::critical_section m_key_images_lock;
|
||||
key_image_cache m_key_images;
|
||||
mutable epee::critical_section m_remove_stuck_txs_lock;
|
||||
|
||||
|
||||
|
|
|
|||
94
src/currency_core/tx_semantic_validation.cpp
Normal file
94
src/currency_core/tx_semantic_validation.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
|
||||
#include "tx_semantic_validation.h"
|
||||
#include "currency_format_utils.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_tx_extra(const transaction& tx)
|
||||
{
|
||||
tx_extra_info ei = AUTO_VAL_INIT(ei);
|
||||
bool r = parse_and_validate_tx_extra(tx, ei);
|
||||
if (!r)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool check_tx_inputs_keyimages_diff(const transaction& tx)
|
||||
{
|
||||
std::unordered_set<crypto::key_image> ki;
|
||||
BOOST_FOREACH(const auto& in, tx.vin)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
|
||||
if (!ki.insert(tokey_in.k_image).second)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool validate_tx_semantic(const transaction& tx, size_t tx_block_size)
|
||||
{
|
||||
if (!tx.vin.size())
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_inputs_types_supported(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("unsupported input types for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_outs_valid(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_money_overflow(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx has money overflow, rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t amount_in = 0;
|
||||
get_inputs_money_amount(tx, amount_in);
|
||||
uint64_t amount_out = get_outs_money_amount(tx);
|
||||
|
||||
if (amount_in < amount_out)
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tx_block_size >= CURRENCY_MAX_TRANSACTION_BLOB_SIZE)
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx has too big size " << tx_block_size << ", expected no bigger than " << CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE);
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if tx use different key images
|
||||
if (!check_tx_inputs_keyimages_diff(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx inputs have the same key images");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!check_tx_extra(tx))
|
||||
{
|
||||
LOG_PRINT_RED_L0("tx has wrong extra, rejected");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
16
src/currency_core/tx_semantic_validation.h
Normal file
16
src/currency_core/tx_semantic_validation.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) 2018-2019 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "currency_format_utils_transactions.h"
|
||||
|
||||
|
||||
namespace currency
|
||||
{
|
||||
//check correct values, amounts and all lightweight checks not related with database
|
||||
bool validate_tx_semantic(const transaction& tx, size_t tx_block_size);
|
||||
}
|
||||
|
|
@ -25,7 +25,11 @@ namespace currency
|
|||
bool m_verification_failed; //bad block, should drop connection
|
||||
bool m_marked_as_orphaned;
|
||||
bool m_already_exists;
|
||||
bool added_to_altchain;
|
||||
uint64_t height_difference;
|
||||
bool m_added_to_altchain;
|
||||
uint64_t m_height_difference;
|
||||
//this is work like a first-level cache for transactions while block is getting handled. It lets transactions
|
||||
//associated with the block to get handled directly to core without being handled by tx_pool(which makes full
|
||||
//inputs validation, including signatures check)
|
||||
transactions_map m_onboard_transactions;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -305,14 +305,22 @@ namespace currency
|
|||
//now actually process block
|
||||
for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++)
|
||||
{
|
||||
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
m_core.handle_incoming_tx(*tx_blob_it, tvc, true);
|
||||
if(tvc.m_verification_failed)
|
||||
if (tx_blob_it->size() > CURRENCY_MAX_TRANSACTION_BLOB_SIZE)
|
||||
{
|
||||
LOG_PRINT_L0("Block verification failed: transaction verification failed, dropping connection");
|
||||
LOG_ERROR("WRONG TRANSACTION BLOB, too big size " << tx_blob_it->size() << ", rejected");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
crypto::hash tx_hash = null_hash;
|
||||
transaction tx;
|
||||
if (!parse_and_validate_tx_from_blob(*tx_blob_it, tx, tx_hash))
|
||||
{
|
||||
LOG_ERROR("WRONG TRANSACTION BLOB, Failed to parse, rejected");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
bvc.m_onboard_transactions[tx_hash] = tx;
|
||||
}
|
||||
|
||||
m_core.pause_mine();
|
||||
|
|
@ -327,10 +335,10 @@ namespace currency
|
|||
LOG_PRINT_GREEN("[HANDLE]NOTIFY_NEW_BLOCK EXTRA " << block_id
|
||||
<< " bvc.m_added_to_main_chain=" << bvc.m_added_to_main_chain
|
||||
//<< ", prevalidate_result=" << prevalidate_relayed
|
||||
<< ", bvc.added_to_altchain=" << bvc.added_to_altchain
|
||||
<< ", bvc.added_to_altchain=" << bvc.m_added_to_altchain
|
||||
<< ", bvc.m_marked_as_orphaned=" << bvc.m_marked_as_orphaned, LOG_LEVEL_2);
|
||||
|
||||
if (bvc.m_added_to_main_chain || (bvc.added_to_altchain && bvc.height_difference < 2))
|
||||
if (bvc.m_added_to_main_chain || (bvc.m_added_to_altchain && bvc.m_height_difference < 2))
|
||||
{
|
||||
if (true/*!prevalidate_relayed*/)
|
||||
{
|
||||
|
|
@ -521,27 +529,36 @@ namespace currency
|
|||
{
|
||||
CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Blocks processing interrupted, connection dropped");
|
||||
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
//process transactions
|
||||
TIME_MEASURE_START(transactions_process_time);
|
||||
for (const auto& tx_blob : block_entry.txs)
|
||||
{
|
||||
CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Block txs processing interrupted, connection dropped");
|
||||
|
||||
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
m_core.handle_incoming_tx(tx_blob, tvc, true);
|
||||
if(tvc.m_verification_failed)
|
||||
crypto::hash tx_id = null_hash;
|
||||
transaction tx = AUTO_VAL_INIT(tx);
|
||||
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_id))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
|
||||
LOG_ERROR_CCONTEXT("failed to parse tx: "
|
||||
<< string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
bvc.m_onboard_transactions[tx_id] = tx;
|
||||
// tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
// m_core.handle_incoming_tx(tx_blob, tvc, true);
|
||||
// if(tvc.m_verification_failed)
|
||||
// {
|
||||
// LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = "
|
||||
// << string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
|
||||
// m_p2p->drop_connection(context);
|
||||
// return 1;
|
||||
// }
|
||||
}
|
||||
TIME_MEASURE_FINISH(transactions_process_time);
|
||||
|
||||
//process block
|
||||
TIME_MEASURE_START(block_process_time);
|
||||
block_verification_context bvc = boost::value_initialized<block_verification_context>();
|
||||
|
||||
m_core.handle_incoming_block(block_entry.block, bvc, false);
|
||||
if (count > 2 && bvc.m_already_exists)
|
||||
|
|
|
|||
|
|
@ -147,7 +147,6 @@ int main(int argc, char* argv[])
|
|||
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);
|
||||
command_line::add_arg(desc_cmd_sett, command_line::arg_db_engine);
|
||||
|
||||
|
||||
arg_market_disable.default_value = true;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ namespace tools
|
|||
return m_rpc.on_submitblock(req, rsp, m_err_stub, m_cntxt_stub);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool call_COMMAND_RPC_SUBMITBLOCK2(const currency::COMMAND_RPC_SUBMITBLOCK2::request& req, currency::COMMAND_RPC_SUBMITBLOCK2::response& rsp) override
|
||||
{
|
||||
return m_rpc.on_submitblock2(req, rsp, m_err_stub, m_cntxt_stub);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool call_COMMAND_RPC_GET_POS_MINING_DETAILS(const currency::COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, currency::COMMAND_RPC_GET_POS_MINING_DETAILS::response& rsp) override
|
||||
{
|
||||
return m_rpc.on_get_pos_mining_details(req, rsp, m_cntxt_stub);
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ bool daemon_backend::init(int argc, char* argv[], view::i_view* pview_handler)
|
|||
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_sett, command_line::arg_show_details);
|
||||
command_line::add_arg(desc_cmd_sett, command_line::arg_db_engine);
|
||||
command_line::add_arg(desc_cmd_sett, arg_alloc_win_console);
|
||||
command_line::add_arg(desc_cmd_sett, arg_html_folder);
|
||||
command_line::add_arg(desc_cmd_sett, arg_xcode_stub);
|
||||
|
|
@ -656,7 +655,7 @@ std::string daemon_backend::get_my_offers(const bc_services::core_offers_filter&
|
|||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
|
||||
std::string daemon_backend::open_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr)
|
||||
std::string daemon_backend::open_wallet(const std::wstring& path, const std::string& password, uint64_t txs_to_return, view::open_wallet_response& owr)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> w(new tools::wallet2());
|
||||
owr.wallet_id = m_wallet_id_counter++;
|
||||
|
|
@ -678,8 +677,7 @@ std::string daemon_backend::open_wallet(const std::wstring& path, const std::str
|
|||
try
|
||||
{
|
||||
w->load(path, password);
|
||||
w->get_recent_transfers_history(owr.recent_history.history, 0, 0);
|
||||
owr.recent_history.total_history_items = w->get_recent_transfers_total_count();
|
||||
w->get_recent_transfers_history(owr.recent_history.history, 0, txs_to_return, owr.recent_history.total_history_items);
|
||||
//w->get_unconfirmed_transfers(owr.recent_history.unconfirmed);
|
||||
w->get_unconfirmed_transfers(owr.recent_history.history);
|
||||
//workaround for missed fee
|
||||
|
|
@ -717,7 +715,7 @@ std::string daemon_backend::get_recent_transfers(size_t wallet_id, uint64_t offs
|
|||
return API_RETURN_CODE_CORE_BUSY;
|
||||
}
|
||||
|
||||
w->get()->get_recent_transfers_history(tr_hist.history, offset, count);
|
||||
w->get()->get_recent_transfers_history(tr_hist.history, offset, count, tr_hist.total_history_items);
|
||||
//workaround for missed fee
|
||||
for (auto & he : tr_hist.history)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ public:
|
|||
bool start();
|
||||
bool stop();
|
||||
bool send_stop_signal();
|
||||
std::string open_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr);
|
||||
std::string open_wallet(const std::wstring& path, const std::string& password, uint64_t txs_to_return, view::open_wallet_response& owr);
|
||||
std::string generate_wallet(const std::wstring& path, const std::string& password, view::open_wallet_response& owr);
|
||||
std::string restore_wallet(const std::wstring& path, const std::string& password, const std::string& restore_key, view::open_wallet_response& owr);
|
||||
std::string run_wallet(uint64_t wallet_id);
|
||||
|
|
|
|||
|
|
@ -1602,7 +1602,7 @@ QString MainWindow::open_wallet(const QString& param)
|
|||
//return que_call2<view::open_wallet_request>("open_wallet", param, [this](const view::open_wallet_request& owd, view::api_response& ar){
|
||||
PREPARE_ARG_FROM_JSON(view::open_wallet_request, owd);
|
||||
PREPARE_RESPONSE(view::open_wallet_response, ar);
|
||||
ar.error_code = m_backend.open_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, ar.response_data);
|
||||
ar.error_code = m_backend.open_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.txs_to_return, ar.response_data);
|
||||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
|
@ -1746,7 +1746,7 @@ QString MainWindow::get_recent_transfers(const QString& param)
|
|||
LOG_API_TIMING();
|
||||
PREPARE_ARG_FROM_JSON(view::get_recent_transfers_request, a);
|
||||
PREPARE_RESPONSE(view::transfers_array, ar);
|
||||
ar.error_code = m_backend.get_recent_transfers(a.wallet_id, a.offest, a.count, ar.response_data);
|
||||
ar.error_code = m_backend.get_recent_transfers(a.wallet_id, a.offset, a.count, ar.response_data);
|
||||
return MAKE_RESPONSE(ar);
|
||||
CATCH_ENTRY_FAIL_API_RESPONCE();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -373,22 +373,24 @@ public:
|
|||
{
|
||||
std::string pass;
|
||||
std::string path;
|
||||
uint64_t txs_to_return;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(pass)
|
||||
KV_SERIALIZE(path)
|
||||
KV_SERIALIZE(txs_to_return)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct get_recent_transfers_request
|
||||
{
|
||||
uint64_t wallet_id;
|
||||
uint64_t offest;
|
||||
uint64_t offset;
|
||||
uint64_t count;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(wallet_id)
|
||||
KV_SERIALIZE(offest)
|
||||
KV_SERIALIZE(offset)
|
||||
KV_SERIALIZE(count)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ $themes: (
|
|||
tooltipCriticalBackgroundColor: #5f1d1d,
|
||||
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5),
|
||||
modalBackground: url(~src/assets/images/background-dark.png),
|
||||
closeButtonColor: #556576
|
||||
closeButtonColor: #556576,
|
||||
hoverPage: #3a485a
|
||||
),
|
||||
gray: (
|
||||
bodyBackgroundColor: #101417,
|
||||
|
|
@ -109,7 +110,8 @@ $themes: (
|
|||
tooltipCriticalBackgroundColor: #4c1919,
|
||||
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5),
|
||||
modalBackground: url(~src/assets/images/background-gray.png),
|
||||
closeButtonColor: #515960
|
||||
closeButtonColor: #515960,
|
||||
hoverPage: #383e43
|
||||
),
|
||||
white: (
|
||||
bodyBackgroundColor: #eeeeee,
|
||||
|
|
@ -165,7 +167,8 @@ $themes: (
|
|||
tooltipCriticalBackgroundColor: #e53935,
|
||||
tooltipShadow: 0 0 1rem rgba(120, 120, 120, 0.5),
|
||||
modalBackground: url(~src/assets/images/background-white.png),
|
||||
closeButtonColor: #43454b
|
||||
closeButtonColor: #43454b,
|
||||
hoverPage: #ffffff
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,41 @@ app-wallet {
|
|||
background-color: themed(contentBackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(contentBackgroundColor);
|
||||
}
|
||||
|
||||
.pagination {
|
||||
|
||||
@include themify($themes) {
|
||||
border-top: 0.2rem solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
button {
|
||||
@include themify($themes) {
|
||||
background-color: themed(transparentButtonBorderColor);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
&.active {
|
||||
@include themify($themes) {
|
||||
background-color: themed(tableBackgroundColor);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include themify($themes) {
|
||||
background-color: themed(hoverPage);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -5800,8 +5800,8 @@ __webpack_require__.r(__webpack_exports__);
|
|||
/*! no static exports found */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
__webpack_require__(/*! C:\Users\Admin\Desktop\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
|
||||
module.exports = __webpack_require__(/*! C:\Users\Admin\Desktop\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
|
||||
__webpack_require__(/*! c:\Users\Admin\Desktop\zano\src\gui\qt-daemon\html_source\src\polyfills.ts */"./src/polyfills.ts");
|
||||
module.exports = __webpack_require__(/*! c:\Users\Admin\Desktop\zano\src\gui\qt-daemon\html_source\node_modules\@angular-devkit\build-angular\src\angular-cli-files\models\jit-polyfills.js */"./node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/jit-polyfills.js");
|
||||
|
||||
|
||||
/***/ })
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -21,12 +21,17 @@ export class Wallet {
|
|||
new_contracts?: number;
|
||||
|
||||
history: Array<Transaction> = [];
|
||||
total_history_item?: number;
|
||||
pages = [];
|
||||
totalPages: number;
|
||||
currentPage: number;
|
||||
excluded_history: Array<Transaction> = [];
|
||||
|
||||
contracts: Array<Contract> = [];
|
||||
|
||||
progress?: number;
|
||||
loaded?: boolean;
|
||||
restore?: boolean;
|
||||
|
||||
send_data?: any = {
|
||||
address: null,
|
||||
|
|
|
|||
|
|
@ -374,10 +374,11 @@ export class BackendService {
|
|||
this.runCommand('generate_wallet', params, callback);
|
||||
}
|
||||
|
||||
openWallet(path, pass, testEmpty, callback) {
|
||||
openWallet(path, pass, txs_to_return, testEmpty, callback) {
|
||||
const params = {
|
||||
path: path,
|
||||
pass: pass
|
||||
pass: pass,
|
||||
txs_to_return: txs_to_return
|
||||
};
|
||||
params['testEmpty'] = !!(testEmpty);
|
||||
this.runCommand('open_wallet', params, callback);
|
||||
|
|
@ -631,6 +632,15 @@ export class BackendService {
|
|||
}
|
||||
}
|
||||
|
||||
getRecentTransfers( id, offset, count, callback) {
|
||||
const params = {
|
||||
wallet_id: id,
|
||||
offset: offset,
|
||||
count: count
|
||||
};
|
||||
this.runCommand('get_recent_transfers', params, callback);
|
||||
}
|
||||
|
||||
getPoolInfo(callback) {
|
||||
this.runCommand('get_tx_pool_info', {}, callback);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
/* tslint:disable:no-unused-variable */
|
||||
|
||||
import { TestBed, async, inject } from '@angular/core/testing';
|
||||
import { PaginationService } from './pagination.service';
|
||||
|
||||
describe('Service: Pagination', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [PaginationService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should ...', inject([PaginationService], (service: PaginationService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { Injectable, NgZone } from '@angular/core';
|
||||
import { VariablesService } from './variables.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PaginationService {
|
||||
|
||||
constructor(
|
||||
private variables: VariablesService,
|
||||
private ngZone: NgZone
|
||||
) { }
|
||||
|
||||
paginate(currentPage = 1) {
|
||||
|
||||
if (currentPage < 1) {
|
||||
currentPage = 1;
|
||||
} else if (currentPage > this.variables.currentWallet.totalPages) {
|
||||
currentPage = this.variables.currentWallet.totalPages;
|
||||
}
|
||||
|
||||
let startPage: number, endPage: number;
|
||||
if (this.variables.currentWallet.totalPages <= this.variables.maxPages) {
|
||||
startPage = 1;
|
||||
endPage = this.variables.currentWallet.totalPages;
|
||||
} else {
|
||||
const maxPagesBeforeCurrentPage = Math.floor(this.variables.maxPages / 2);
|
||||
const maxPagesAfterCurrentPage = Math.ceil(this.variables.maxPages / 2) - 1;
|
||||
if (currentPage <= maxPagesBeforeCurrentPage) {
|
||||
startPage = 1;
|
||||
this.variables.currentWallet.totalPages > this.variables.maxPages
|
||||
? endPage = this.variables.maxPages
|
||||
: endPage = this.variables.currentWallet.totalPages
|
||||
;
|
||||
} else if (currentPage + maxPagesAfterCurrentPage >= this.variables.currentWallet.totalPages) {
|
||||
startPage = this.variables.currentWallet.totalPages - this.variables.maxPages + 1;
|
||||
endPage = this.variables.currentWallet.totalPages;
|
||||
} else {
|
||||
startPage = currentPage - maxPagesBeforeCurrentPage;
|
||||
endPage = currentPage + maxPagesAfterCurrentPage;
|
||||
}
|
||||
}
|
||||
this.ngZone.run(() => {
|
||||
this.variables.currentWallet.pages = Array.from(Array((endPage + 1) - startPage).keys()).map(i => startPage + i);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -45,6 +45,9 @@ export class VariablesService {
|
|||
wallets: []
|
||||
};
|
||||
|
||||
public count = 40;
|
||||
public maxPages = 5;
|
||||
|
||||
public wallets: Array<Wallet> = [];
|
||||
public currentWallet: Wallet;
|
||||
public selectWallet: number;
|
||||
|
|
|
|||
|
|
@ -158,6 +158,17 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
wallet.loaded = false;
|
||||
} else if (wallet.progress === 100) {
|
||||
wallet.loaded = true;
|
||||
if (wallet.total_history_item) {
|
||||
wallet.totalPages = Math.ceil( wallet.total_history_item / this.variablesService.count);
|
||||
wallet.totalPages > this.variablesService.maxPages
|
||||
? wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: wallet.pages = new Array(wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
} else if (wallet.restore) {
|
||||
wallet.totalPages = Math.ceil( wallet.history.length / this.variablesService.count);
|
||||
wallet.totalPages > this.variablesService.maxPages
|
||||
? wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: wallet.pages = new Array(wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -216,7 +227,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
const tr_info = data.ti;
|
||||
|
||||
const wallet = this.variablesService.getWallet(wallet_id);
|
||||
|
||||
if (wallet) {
|
||||
this.ngZone.run(() => {
|
||||
|
||||
|
|
@ -236,6 +246,13 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
tr_exists = (!tr_exists) ? wallet.history.some(elem => elem.tx_hash === tr_info.tx_hash) : tr_exists;
|
||||
|
||||
wallet.prepareHistory([tr_info]);
|
||||
if (wallet.restore) {
|
||||
wallet.total_history_item = wallet.history.length;
|
||||
wallet.totalPages = Math.ceil( wallet.total_history_item / this.variablesService.count);
|
||||
wallet.totalPages > this.variablesService.maxPages
|
||||
? wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: wallet.pages = new Array(wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
}
|
||||
|
||||
if (tr_info.hasOwnProperty('contract')) {
|
||||
const exp_med_ts = this.variablesService.exp_med_ts;
|
||||
|
|
|
|||
|
|
@ -78,6 +78,10 @@ export class CreateWalletComponent implements OnInit {
|
|||
generate_data['wi'].tracking_hey
|
||||
);
|
||||
this.variablesService.opening_wallet.alias = this.backend.getWalletAlias(generate_data['wi'].address);
|
||||
this.variablesService.opening_wallet.total_history_item = 0;
|
||||
this.variablesService.opening_wallet.pages = new Array(1).fill(1);
|
||||
this.variablesService.opening_wallet.totalPages = 1;
|
||||
this.variablesService.opening_wallet.currentPage = 1;
|
||||
this.ngZone.run(() => {
|
||||
this.walletSaved = true;
|
||||
this.progressWidth = '50%';
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
let openWallets = 0;
|
||||
let runWallets = 0;
|
||||
walletData.forEach((wallet, wallet_index) => {
|
||||
this.backend.openWallet(wallet.path, wallet.pass, true, (open_status, open_data, open_error) => {
|
||||
this.backend.openWallet(wallet.path, wallet.pass, this.variablesService.count, true, (open_status, open_data, open_error) => {
|
||||
if (open_status || open_error === 'FILE_RESTORED') {
|
||||
openWallets++;
|
||||
this.ngZone.run(() => {
|
||||
|
|
@ -177,8 +177,18 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
} else {
|
||||
new_wallet.staking = false;
|
||||
}
|
||||
new_wallet.currentPage = 1;
|
||||
if (open_data.recent_history && open_data.recent_history.history) {
|
||||
new_wallet.total_history_item = open_data.recent_history.total_history_items;
|
||||
new_wallet.totalPages = Math.ceil( open_data.recent_history.total_history_items / this.variablesService.count);
|
||||
new_wallet.totalPages > this.variablesService.maxPages
|
||||
? new_wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: new_wallet.pages = new Array(new_wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
new_wallet.prepareHistory(open_data.recent_history.history);
|
||||
} else {
|
||||
new_wallet.total_history_item = 0;
|
||||
new_wallet.pages = new Array(1).fill(1);
|
||||
new_wallet.totalPages = 1;
|
||||
}
|
||||
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
|
||||
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export class OpenWalletModalComponent implements OnInit {
|
|||
this.wallet = this.wallets[0];
|
||||
this.wallet.pass = '';
|
||||
|
||||
this.backend.openWallet(this.wallet.path, '', true, (status, data, error) => {
|
||||
this.backend.openWallet(this.wallet.path, '', this.variablesService.count, true, (status, data, error) => {
|
||||
if (error === 'FILE_NOT_FOUND') {
|
||||
this.wallet.notFound = true;
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ export class OpenWalletModalComponent implements OnInit {
|
|||
if (this.wallets.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.backend.openWallet(this.wallet.path, this.wallet.pass, false, (open_status, open_data, open_error) => {
|
||||
this.backend.openWallet(this.wallet.path, this.wallet.pass, this.variablesService.count, false, (open_status, open_data, open_error) => {
|
||||
if (open_error && open_error === 'FILE_NOT_FOUND') {
|
||||
let error_translate = this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND1');
|
||||
error_translate += ':<br>' + this.wallet.path;
|
||||
|
|
@ -87,7 +87,16 @@ export class OpenWalletModalComponent implements OnInit {
|
|||
);
|
||||
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
|
||||
if (open_data.recent_history && open_data.recent_history.history) {
|
||||
new_wallet.total_history_item = open_data.recent_history.total_history_items;
|
||||
new_wallet.totalPages = Math.ceil( open_data.recent_history.total_history_items / this.variablesService.count);
|
||||
new_wallet.totalPages > this.variablesService.maxPages
|
||||
? new_wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: new_wallet.pages = new Array(new_wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
new_wallet.prepareHistory(open_data.recent_history.history);
|
||||
} else {
|
||||
new_wallet.total_history_item = 0;
|
||||
new_wallet.pages = new Array(1).fill(1);
|
||||
new_wallet.totalPages = 1;
|
||||
}
|
||||
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
|
||||
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export class OpenWalletComponent implements OnInit, OnDestroy {
|
|||
|
||||
openWallet() {
|
||||
if (this.openForm.valid && this.openForm.get('name').value.length <= this.variablesService.maxWalletNameLength) {
|
||||
this.backend.openWallet(this.filePath, this.openForm.get('password').value, false, (open_status, open_data, open_error) => {
|
||||
this.backend.openWallet(this.filePath, this.openForm.get('password').value, this.variablesService.count, false, (open_status, open_data, open_error) => {
|
||||
if (open_error && open_error === 'FILE_NOT_FOUND') {
|
||||
let error_translate = this.translate.instant('OPEN_WALLET.FILE_NOT_FOUND1');
|
||||
error_translate += ':<br>' + this.filePath;
|
||||
|
|
@ -97,8 +97,18 @@ export class OpenWalletComponent implements OnInit, OnDestroy {
|
|||
open_data['wi'].tracking_hey
|
||||
);
|
||||
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
|
||||
new_wallet.currentPage = 1;
|
||||
if (open_data.recent_history && open_data.recent_history.history) {
|
||||
new_wallet.total_history_item = open_data.recent_history.total_history_items;
|
||||
new_wallet.totalPages = Math.ceil( open_data.recent_history.total_history_items / this.variablesService.count);
|
||||
new_wallet.totalPages > this.variablesService.maxPages
|
||||
? new_wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: new_wallet.pages = new Array(new_wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
new_wallet.prepareHistory(open_data.recent_history.history);
|
||||
} else {
|
||||
new_wallet.total_history_item = 0;
|
||||
new_wallet.pages = new Array(1).fill(1);
|
||||
new_wallet.totalPages = 1;
|
||||
}
|
||||
this.backend.getContracts(open_data.wallet_id, (contracts_status, contracts_data) => {
|
||||
if (contracts_status && contracts_data.hasOwnProperty('contracts')) {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,16 @@ export class RestoreWalletComponent implements OnInit {
|
|||
restore_data['wi'].tracking_hey
|
||||
);
|
||||
this.variablesService.opening_wallet.alias = this.backend.getWalletAlias(this.variablesService.opening_wallet.address);
|
||||
this.variablesService.opening_wallet.pages = new Array(1).fill(1);
|
||||
this.variablesService.opening_wallet.totalPages = 1;
|
||||
this.variablesService.opening_wallet.currentPage = 1;
|
||||
this.variablesService.opening_wallet.total_history_item = 0;
|
||||
this.variablesService.opening_wallet.restore = true;
|
||||
if (restore_data.recent_history && restore_data.recent_history.history) {
|
||||
this.variablesService.opening_wallet.totalPages = Math.ceil( restore_data.recent_history.total_history_items / this.variablesService.count);
|
||||
this.variablesService.opening_wallet.totalPages > this.variablesService.maxPages
|
||||
? this.variablesService.opening_wallet.pages = new Array(5).fill(1).map((value, index) => value + index)
|
||||
: this.variablesService.opening_wallet.pages = new Array(this.variablesService.opening_wallet.totalPages).fill(1).map((value, index) => value + index);
|
||||
this.variablesService.opening_wallet.prepareHistory(restore_data.recent_history.history);
|
||||
}
|
||||
this.backend.getContracts(this.variablesService.opening_wallet.wallet_id, (contracts_status, contracts_data) => {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,16 @@
|
|||
<div #scrolledContent class="tabs-content scrolled-content">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<div *ngIf="activeTab === 'history'" class="pagination-wrapper">
|
||||
<div class="pagination">
|
||||
<button [disabled]="variablesService.currentWallet.currentPage === 1" (click)="setPage(variablesService.currentWallet.currentPage - 1)"><</button>
|
||||
<ng-container *ngFor="let page of variablesService.currentWallet.pages">
|
||||
<button [ngClass]="{ 'active': variablesService.currentWallet.currentPage === page }"
|
||||
(click)="setPage(page)">{{page}}</button>
|
||||
</ng-container>
|
||||
<button [disabled]="variablesService.currentWallet.currentPage === variablesService.currentWallet.totalPages" (click)="setPage(variablesService.currentWallet.currentPage + 1)">></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-confirm-modal *ngIf="isModalDialogVisible" [title]=" 'WALLET.CONFIRM.TITLE' | translate " [message]=" 'WALLET.CONFIRM.MESSAGE' | translate " (confirmed)="confirmed($event)"></app-confirm-modal>
|
||||
|
|
|
|||
|
|
@ -238,4 +238,18 @@
|
|||
overflow-x: hidden;
|
||||
overflow-y: overlay;
|
||||
}
|
||||
|
||||
|
||||
.pagination-wrapper {
|
||||
.pagination {
|
||||
padding: 1rem;
|
||||
button {
|
||||
margin-right: 0.5rem;
|
||||
padding: 0;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import {Component, OnInit, OnDestroy, NgZone, ViewChild, ElementRef} from '@angular/core';
|
||||
import {ActivatedRoute, Router, RoutesRecognized} from '@angular/router';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {BackendService} from '../_helpers/services/backend.service';
|
||||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {IntToMoneyPipe} from '../_helpers/pipes/int-to-money.pipe';
|
||||
import {Subscription} from 'rxjs';
|
||||
import { Component, OnInit, OnDestroy, NgZone, ViewChild, ElementRef } from '@angular/core';
|
||||
import { ActivatedRoute, Router, RoutesRecognized } from '@angular/router';
|
||||
import { VariablesService } from '../_helpers/services/variables.service';
|
||||
import { BackendService } from '../_helpers/services/backend.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { IntToMoneyPipe } from '../_helpers/pipes/int-to-money.pipe';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import icons from '../../assets/icons/icons.json';
|
||||
import { PaginationService } from '../_helpers/services/pagination.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-wallet',
|
||||
|
|
@ -22,6 +23,9 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
copyAnimationTimeout;
|
||||
balanceTooltip;
|
||||
isModalDialogVisible = false;
|
||||
activeTab = 'history';
|
||||
|
||||
public currentPage = 1;
|
||||
|
||||
@ViewChild('scrolledContent') private scrolledContent: ElementRef;
|
||||
|
||||
|
|
@ -90,8 +94,9 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
public variablesService: VariablesService,
|
||||
private ngZone: NgZone,
|
||||
private translate: TranslateService,
|
||||
private intToMoneyPipe: IntToMoneyPipe
|
||||
) {}
|
||||
private intToMoneyPipe: IntToMoneyPipe,
|
||||
private pagination: PaginationService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.subRouting1 = this.route.params.subscribe(params => {
|
||||
|
|
@ -103,7 +108,8 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
this.subRouting2 = this.router.events.subscribe(val => {
|
||||
if (val instanceof RoutesRecognized) {
|
||||
if ( val.state.root.firstChild && val.state.root.firstChild.firstChild ) {
|
||||
this.activeTab = val.urlAfterRedirects.split('/').pop();
|
||||
if (val.state.root.firstChild && val.state.root.firstChild.firstChild) {
|
||||
for (let i = 0; i < this.tabs.length; i++) {
|
||||
this.tabs[i].active = (this.tabs[i].link === '/' + val.state.root.firstChild.firstChild.url[0].path);
|
||||
}
|
||||
|
|
@ -137,7 +143,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
tab.active = false;
|
||||
});
|
||||
this.tabs[index].active = true;
|
||||
this.ngZone.run( () => {
|
||||
this.ngZone.run(() => {
|
||||
this.scrolledContent.nativeElement.scrollTop = 0;
|
||||
this.router.navigate(['wallet/' + this.walletID + this.tabs[index].link]);
|
||||
});
|
||||
|
|
@ -159,11 +165,11 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
this.balanceTooltip = document.createElement('div');
|
||||
const available = document.createElement('span');
|
||||
available.setAttribute('class', 'available');
|
||||
available.innerHTML = this.translate.instant('WALLET.AVAILABLE_BALANCE', {available: this.intToMoneyPipe.transform(this.variablesService.currentWallet.unlocked_balance), currency: this.variablesService.defaultCurrency});
|
||||
available.innerHTML = this.translate.instant('WALLET.AVAILABLE_BALANCE', { available: this.intToMoneyPipe.transform(this.variablesService.currentWallet.unlocked_balance), currency: this.variablesService.defaultCurrency });
|
||||
this.balanceTooltip.appendChild(available);
|
||||
const locked = document.createElement('span');
|
||||
locked.setAttribute('class', 'locked');
|
||||
locked.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE', {locked: this.intToMoneyPipe.transform(this.variablesService.currentWallet.balance.minus(this.variablesService.currentWallet.unlocked_balance)), currency: this.variablesService.defaultCurrency});
|
||||
locked.innerHTML = this.translate.instant('WALLET.LOCKED_BALANCE', { locked: this.intToMoneyPipe.transform(this.variablesService.currentWallet.balance.minus(this.variablesService.currentWallet.unlocked_balance)), currency: this.variablesService.defaultCurrency });
|
||||
this.balanceTooltip.appendChild(locked);
|
||||
const link = document.createElement('span');
|
||||
link.setAttribute('class', 'link');
|
||||
|
|
@ -215,6 +221,29 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
public setPage(pageNumber: number) {
|
||||
if (pageNumber === this.variablesService.currentWallet.currentPage) {
|
||||
return;
|
||||
}
|
||||
this.variablesService.currentWallet.currentPage = pageNumber;
|
||||
this.backend.getRecentTransfers(
|
||||
this.walletID,
|
||||
(this.variablesService.currentWallet.currentPage - 1) * this.variablesService.count,
|
||||
this.variablesService.count, (status, data) => {
|
||||
if (status && data.total_history_items) {
|
||||
this.variablesService.currentWallet.history.splice(0, this.variablesService.currentWallet.history.length);
|
||||
this.ngZone.run(() => {
|
||||
this.pagination.paginate(this.variablesService.currentWallet.currentPage);
|
||||
if (data.history.length !== 0) {
|
||||
this.variablesService.currentWallet.restore = false;
|
||||
this.variablesService.currentWallet.total_history_item = data.total_history_items;
|
||||
this.variablesService.currentWallet.prepareHistory(data.history);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subRouting1.unsubscribe();
|
||||
this.subRouting2.unsubscribe();
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ $themes: (
|
|||
tooltipCriticalBackgroundColor: #5f1d1d,
|
||||
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5),
|
||||
modalBackground: url(~src/assets/images/background-dark.png),
|
||||
closeButtonColor: #556576
|
||||
closeButtonColor: #556576,
|
||||
hoverPage: #3a485a
|
||||
),
|
||||
gray: (
|
||||
bodyBackgroundColor: #101417,
|
||||
|
|
@ -109,7 +110,8 @@ $themes: (
|
|||
tooltipCriticalBackgroundColor: #4c1919,
|
||||
tooltipShadow: 0 0 1rem rgba(0, 0, 0, 0.5),
|
||||
modalBackground: url(~src/assets/images/background-gray.png),
|
||||
closeButtonColor: #515960
|
||||
closeButtonColor: #515960,
|
||||
hoverPage: #383e43
|
||||
),
|
||||
white: (
|
||||
bodyBackgroundColor: #eeeeee,
|
||||
|
|
@ -165,7 +167,8 @@ $themes: (
|
|||
tooltipCriticalBackgroundColor: #e53935,
|
||||
tooltipShadow: 0 0 1rem rgba(120, 120, 120, 0.5),
|
||||
modalBackground: url(~src/assets/images/background-white.png),
|
||||
closeButtonColor: #43454b
|
||||
closeButtonColor: #43454b,
|
||||
hoverPage: #ffffff
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,41 @@ app-wallet {
|
|||
background-color: themed(contentBackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-wrapper {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(contentBackgroundColor);
|
||||
}
|
||||
|
||||
.pagination {
|
||||
|
||||
@include themify($themes) {
|
||||
border-top: 0.2rem solid themed(transparentButtonBorderColor);
|
||||
}
|
||||
|
||||
button {
|
||||
@include themify($themes) {
|
||||
background-color: themed(transparentButtonBorderColor);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
|
||||
&.active {
|
||||
@include themify($themes) {
|
||||
background-color: themed(tableBackgroundColor);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include themify($themes) {
|
||||
background-color: themed(hoverPage);
|
||||
color: themed(mainTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ namespace nodetool
|
|||
m_ip_address{},
|
||||
m_last_stat_request_time{},
|
||||
m_use_only_priority_peers(false),
|
||||
m_peer_livetime{}
|
||||
m_peer_livetime{},
|
||||
m_debug_requests_enabled(false)
|
||||
|
||||
{}
|
||||
|
||||
|
|
|
|||
|
|
@ -100,9 +100,9 @@ namespace nodetool
|
|||
if (m_offline_mode)
|
||||
return false;
|
||||
|
||||
//@#@ workaround
|
||||
//@#@ temporary workaround
|
||||
return true;
|
||||
|
||||
#if 0
|
||||
CRITICAL_REGION_LOCAL(m_blocked_ips_lock);
|
||||
auto it = m_blocked_ips.find(addr);
|
||||
if(it == m_blocked_ips.end())
|
||||
|
|
@ -114,6 +114,7 @@ namespace nodetool
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
|
|
@ -280,10 +281,10 @@ namespace nodetool
|
|||
ADD_HARDCODED_SEED_NODE("94.130.137.230", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("95.217.42.247", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("94.130.160.115", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("207.154.237.82", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("207.154.240.198", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("207.154.255.10", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("207.154.228.141", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("195.201.107.230", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("95.217.46.49", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("159.69.76.144", P2P_DEFAULT_PORT);
|
||||
ADD_HARDCODED_SEED_NODE("144.76.183.143", P2P_DEFAULT_PORT);
|
||||
#else
|
||||
//TODO:
|
||||
ADD_HARDCODED_SEED_NODE("95.217.43.225", P2P_DEFAULT_PORT);
|
||||
|
|
@ -696,7 +697,7 @@ namespace nodetool
|
|||
if(just_take_peerlist)
|
||||
{
|
||||
m_net_server.get_config_object().close(con.m_connection_id);
|
||||
LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK AND CLOSED.", LOG_LEVEL_2);
|
||||
LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK AND CLOSED with peer " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port), LOG_LEVEL_2);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -707,7 +708,7 @@ namespace nodetool
|
|||
m_peerlist.append_with_peer_white(pe_local);
|
||||
//update last seen and push it to peerlist manager
|
||||
|
||||
LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK.", LOG_LEVEL_2);
|
||||
LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK with peer " << string_tools::get_ip_string_from_int32(na.ip) << ":" << string_tools::num_to_string_fast(na.port), LOG_LEVEL_2);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -793,28 +793,45 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
wide_difficulty_type dt = 0;
|
||||
currency::pos_entry pe = AUTO_VAL_INIT(pe);
|
||||
pe.amount = req.pos_amount;
|
||||
pe.index = req.pos_index;
|
||||
pe.stake_unlock_time = req.stake_unlock_time;
|
||||
//pe.keyimage key image will be set in the wallet
|
||||
//pe.wallet_index is not included in serialization map, TODO: refactoring here
|
||||
|
||||
if (!m_core.get_block_template(b, miner_address, stakeholder_address, dt, res.height, req.extra_text, req.pos_block, pe))
|
||||
create_block_template_params params = AUTO_VAL_INIT(params);
|
||||
params.miner_address = miner_address;
|
||||
params.stakeholder_address = stakeholder_address;
|
||||
params.ex_nonce = req.extra_text;
|
||||
params.pos = req.pos_block;
|
||||
params.pe.amount = req.pos_amount;
|
||||
params.pe.index = req.pos_index;
|
||||
params.pe.stake_unlock_time = req.stake_unlock_time;
|
||||
//params.pe.keyimage key image will be set in the wallet
|
||||
//params.pe.wallet_index is not included in serialization map, TODO: refactoring here
|
||||
params.pcustom_fill_block_template_func = nullptr;
|
||||
if (req.explicit_transaction.size())
|
||||
{
|
||||
transaction tx = AUTO_VAL_INIT(tx);
|
||||
if (!parse_and_validate_tx_from_blob(req.explicit_transaction, tx))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM;
|
||||
error_resp.message = "Wrong parameters: explicit_transaction is invalid";
|
||||
LOG_ERROR("Failed to parse explicit_transaction blob");
|
||||
return false;
|
||||
}
|
||||
params.explicit_txs.push_back(tx);
|
||||
}
|
||||
|
||||
create_block_template_response resp = AUTO_VAL_INIT(resp);
|
||||
if (!m_core.get_block_template(params, resp))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
|
||||
error_resp.message = "Internal error: failed to create block template";
|
||||
LOG_ERROR("Failed to create block template");
|
||||
return false;
|
||||
}
|
||||
res.difficulty = dt.convert_to<std::string>();
|
||||
blobdata block_blob = t_serializable_object_to_blob(b);
|
||||
|
||||
res.difficulty = resp.diffic.convert_to<std::string>();
|
||||
blobdata block_blob = t_serializable_object_to_blob(resp.b);
|
||||
res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
|
||||
res.prev_hash = string_tools::pod_to_hex(b.prev_id);
|
||||
|
||||
res.prev_hash = string_tools::pod_to_hex(resp.b.prev_id);
|
||||
res.height = resp.height;
|
||||
//calculate epoch seed
|
||||
res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height));
|
||||
|
||||
|
|
@ -851,7 +868,64 @@ namespace currency
|
|||
block_verification_context bvc = AUTO_VAL_INIT(bvc);
|
||||
if(!m_core.handle_block_found(b, &bvc))
|
||||
{
|
||||
if (bvc.added_to_altchain)
|
||||
if (bvc.m_added_to_altchain)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_ADDED_AS_ALTERNATIVE;
|
||||
error_resp.message = "Block added as alternative";
|
||||
return false;
|
||||
}
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED;
|
||||
error_resp.message = "Block not accepted";
|
||||
return false;
|
||||
}
|
||||
//@#@
|
||||
//temporary double check timestamp
|
||||
if (time(NULL) - get_actual_timestamp(b) > 5)
|
||||
{
|
||||
LOG_PRINT_RED_L0("Found block (" << get_block_hash(b) << ") timestamp (" << get_actual_timestamp(b)
|
||||
<< ") is suspiciously less (" << time(NULL) - get_actual_timestamp(b) << ") then curren time( " << time(NULL) << ")");
|
||||
//mark node to make it easier to find it via scanner
|
||||
m_core.get_blockchain_storage().get_performnce_data().epic_failure_happend = true;
|
||||
}
|
||||
//
|
||||
|
||||
|
||||
res.status = "OK";
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool core_rpc_server::on_submitblock2(const COMMAND_RPC_SUBMITBLOCK2::request& req, COMMAND_RPC_SUBMITBLOCK2::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
|
||||
{
|
||||
CHECK_CORE_READY();
|
||||
|
||||
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
if (!parse_and_validate_block_from_blob(req.b, b))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
|
||||
error_resp.message = "Wrong block blob";
|
||||
return false;
|
||||
}
|
||||
|
||||
block_verification_context bvc = AUTO_VAL_INIT(bvc);
|
||||
for (const auto& txblob : req.explicit_txs)
|
||||
{
|
||||
|
||||
crypto::hash tx_hash = AUTO_VAL_INIT(tx_hash);
|
||||
transaction tx = AUTO_VAL_INIT(tx);
|
||||
if (!parse_and_validate_tx_from_blob(txblob.blob, tx, tx_hash))
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB;
|
||||
error_resp.message = "Wrong explicit tx blob";
|
||||
return false;
|
||||
}
|
||||
bvc.m_onboard_transactions[tx_hash] = tx;
|
||||
}
|
||||
|
||||
|
||||
if (!m_core.handle_block_found(b, &bvc))
|
||||
{
|
||||
if (bvc.m_added_to_altchain)
|
||||
{
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_ADDED_AS_ALTERNATIVE;
|
||||
error_resp.message = "Block added as alternative";
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ namespace currency
|
|||
bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_submitblock2(const COMMAND_RPC_SUBMITBLOCK2::request& req, COMMAND_RPC_SUBMITBLOCK2::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, connection_context& cntx);
|
||||
|
|
@ -125,6 +126,7 @@ namespace currency
|
|||
MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH)
|
||||
MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE)
|
||||
MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK)
|
||||
MAP_JON_RPC_WE("submitblock2", on_submitblock2, COMMAND_RPC_SUBMITBLOCK2)
|
||||
MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER)
|
||||
MAP_JON_RPC_WE("getblockheaderbyhash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH)
|
||||
MAP_JON_RPC_WE("getblockheaderbyheight", on_get_block_header_by_height, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "serialization/keyvalue_hexemizer.h"
|
||||
#include "currency_protocol/currency_protocol_defs.h"
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "currency_core/difficulty.h"
|
||||
|
|
@ -770,7 +771,7 @@ namespace currency
|
|||
{
|
||||
struct request
|
||||
{
|
||||
//uint64_t reserve_size; //max 255 bytes
|
||||
blobdata explicit_transaction;
|
||||
std::string extra_text;
|
||||
std::string wallet_address;
|
||||
std::string stakeholder_address;
|
||||
|
|
@ -780,6 +781,7 @@ namespace currency
|
|||
uint64_t stake_unlock_time;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_BLOB_AS_HEX_STRING(explicit_transaction)
|
||||
KV_SERIALIZE(extra_text)
|
||||
KV_SERIALIZE(wallet_address)
|
||||
KV_SERIALIZE(stakeholder_address);
|
||||
|
|
@ -824,6 +826,29 @@ namespace currency
|
|||
};
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_SUBMITBLOCK2
|
||||
{
|
||||
struct request
|
||||
{
|
||||
std::string b; //hex encoded block blob
|
||||
std::list<epee::hexemizer> explicit_txs; //hex encoded tx blobs
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_BLOB_AS_HEX_STRING(b)
|
||||
KV_SERIALIZE(explicit_txs)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string status;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct block_header_response
|
||||
{
|
||||
uint8_t major_version;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ namespace
|
|||
const command_line::arg_descriptor<int> arg_daemon_port = {"daemon-port", "Use daemon instance at port <arg> instead of default", 0};
|
||||
const command_line::arg_descriptor<uint32_t> arg_log_level = {"set-log", "", 0, true};
|
||||
const command_line::arg_descriptor<bool> arg_do_pos_mining = { "do-pos-mining", "Do PoS mining", false, false };
|
||||
const command_line::arg_descriptor<std::string> arg_pos_mining_reward_address = { "pos-mining-reward-address", "Block reward will be sent to the giving address if specified", "" };
|
||||
const command_line::arg_descriptor<std::string> arg_restore_wallet = { "restore-wallet", "Restore wallet from the seed phrase and save it to <arg>", "" };
|
||||
const command_line::arg_descriptor<bool> arg_offline_mode = { "offline-mode", "Don't connect to daemon, work offline (for cold-signing process)", false, true };
|
||||
|
||||
|
|
@ -190,7 +191,7 @@ simple_wallet::simple_wallet()
|
|||
m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _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, _1), "incoming_transfers counts");
|
||||
m_cmd_binder.set_handler("list_recent_transfers", boost::bind(&simple_wallet::list_recent_transfers, this, _1), "list_recent_transfers - Show recent maximum 1000 transfers");
|
||||
m_cmd_binder.set_handler("list_recent_transfers_ex", boost::bind(&simple_wallet::list_recent_transfers_ex, this, _1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt");
|
||||
m_cmd_binder.set_handler("export_recent_transfers", boost::bind(&simple_wallet::export_recent_transfers, this, _1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt");
|
||||
m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, _1), "list_outputs [spent|unspent] - Lists all the outputs that have ever been sent to this wallet if called without arguments, otherwise it lists only the spent or unspent outputs");
|
||||
m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, _1), "dump_transfers - Write transfers in json to dump_transfers.txt");
|
||||
m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, _1), "dump_keyimages - Write key_images in json to dump_key_images.txt");
|
||||
|
|
@ -207,6 +208,8 @@ simple_wallet::simple_wallet()
|
|||
m_cmd_binder.set_handler("fix_collisions", boost::bind(&simple_wallet::fix_collisions, this, _1), "Rescan transfers for key image collisions");
|
||||
m_cmd_binder.set_handler("scan_transfers_for_id", boost::bind(&simple_wallet::scan_transfers_for_id, this, _1), "Rescan transfers for tx_id");
|
||||
m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this, _1), "Rescan transfers for key image");
|
||||
m_cmd_binder.set_handler("print_utxo_distribution", boost::bind(&simple_wallet::print_utxo_distribution, this, _1), "Prints utxo distribution");
|
||||
m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this, _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("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
|
||||
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::integrated_address, this, _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");
|
||||
|
|
@ -688,7 +691,7 @@ bool print_wti(const tools::wallet_public::wallet_transfer_info& wti)
|
|||
|
||||
std::string payment_id_placeholder;
|
||||
if (wti.payment_id.size())
|
||||
payment_id_placeholder = std::string("(payment_id:") + wti.payment_id + ")";
|
||||
payment_id_placeholder = std::string("(payment_id:") + epee::string_tools::buff_to_hex_nodelimer(wti.payment_id) + ")";
|
||||
|
||||
static const std::string separator = ", ";
|
||||
std::string remote_side;
|
||||
|
|
@ -715,7 +718,8 @@ bool simple_wallet::list_recent_transfers(const std::vector<std::string>& args)
|
|||
{
|
||||
std::vector<tools::wallet_public::wallet_transfer_info> unconfirmed;
|
||||
std::vector<tools::wallet_public::wallet_transfer_info> recent;
|
||||
m_wallet->get_recent_transfers_history(recent, 0, 0);
|
||||
uint64_t total = 0;
|
||||
m_wallet->get_recent_transfers_history(recent, 0, 0, total);
|
||||
m_wallet->get_unconfirmed_transfers(unconfirmed);
|
||||
//workaround for missed fee
|
||||
|
||||
|
|
@ -736,11 +740,39 @@ bool simple_wallet::list_recent_transfers(const std::vector<std::string>& args)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::list_recent_transfers_ex(const std::vector<std::string>& args)
|
||||
std::string wti_to_text_line(const tools::wallet_public::wallet_transfer_info& wti)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << (wti.is_income ? "[INC]" : "[OUT]") << "\t"
|
||||
<< epee::misc_utils::get_time_str(wti.timestamp) << "\t"
|
||||
<< print_money(wti.amount) << "\t"
|
||||
<< print_money(wti.fee) << "\t"
|
||||
<< wti.remote_addresses << "\t"
|
||||
<< wti.comment << "\t";
|
||||
return ss.str();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::export_recent_transfers(const std::vector<std::string>& args)
|
||||
{
|
||||
bool export_to_json = true;
|
||||
bool ignore_pos = false;
|
||||
if (args.size())
|
||||
{
|
||||
if (args[0] == "json")
|
||||
export_to_json = true;
|
||||
else if (args[0] == "txt")
|
||||
export_to_json = false;
|
||||
}
|
||||
if (args.size() > 1)
|
||||
{
|
||||
if (args[1] == "ignore-pos")
|
||||
ignore_pos = true;
|
||||
}
|
||||
|
||||
std::vector<tools::wallet_public::wallet_transfer_info> unconfirmed;
|
||||
std::vector<tools::wallet_public::wallet_transfer_info> recent;
|
||||
m_wallet->get_recent_transfers_history(recent, 0, 0);
|
||||
uint64_t total = 0;
|
||||
m_wallet->get_recent_transfers_history(recent, 0, 0, total);
|
||||
m_wallet->get_unconfirmed_transfers(unconfirmed);
|
||||
//workaround for missed fee
|
||||
stringstream ss;
|
||||
|
|
@ -748,17 +780,28 @@ bool simple_wallet::list_recent_transfers_ex(const std::vector<std::string>& arg
|
|||
ss << "Unconfirmed transfers: " << ENDL;
|
||||
for (auto & wti : unconfirmed)
|
||||
{
|
||||
if(ignore_pos && wti.is_mining)
|
||||
continue;
|
||||
if (!wti.fee)
|
||||
wti.fee = currency::get_tx_fee(wti.tx);
|
||||
ss << epee::serialization::store_t_to_json(wti) << ENDL;
|
||||
if(export_to_json)
|
||||
ss << epee::serialization::store_t_to_json(wti) << ENDL;
|
||||
else
|
||||
ss << wti_to_text_line(wti) << ENDL;
|
||||
|
||||
}
|
||||
ss << "Recent transfers: " << ENDL;
|
||||
for (auto & wti : recent)
|
||||
{
|
||||
if (ignore_pos && wti.is_mining)
|
||||
continue;
|
||||
if (!wti.fee)
|
||||
wti.fee = currency::get_tx_fee(wti.tx);
|
||||
|
||||
ss << epee::serialization::store_t_to_json(wti) << ENDL;
|
||||
if (export_to_json)
|
||||
ss << epee::serialization::store_t_to_json(wti) << ENDL;
|
||||
else
|
||||
ss << wti_to_text_line(wti) << ENDL;
|
||||
}
|
||||
LOG_PRINT_GREEN("Storing text to wallet_recent_transfers.txt....", LOG_LEVEL_0);
|
||||
file_io_utils::save_string_to_file(log_space::log_singletone::get_default_log_folder() + "/wallet_recent_transfers.txt", ss.str());
|
||||
|
|
@ -949,6 +992,18 @@ bool simple_wallet::scan_transfers_for_ki(const std::vector<std::string> &args)
|
|||
print_td_list(td);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::print_utxo_distribution(const std::vector<std::string> &args)
|
||||
{
|
||||
std::map<uint64_t, uint64_t> distribution;
|
||||
m_wallet->get_utxo_distribution(distribution);
|
||||
for (auto& e : distribution)
|
||||
{
|
||||
message_writer() << std::left << setw(25) << print_money(e.first) << "|" << e.second;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::get_transfer_info(const std::vector<std::string> &args)
|
||||
{
|
||||
|
|
@ -1261,7 +1316,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
|||
bool simple_wallet::show_seed(const std::vector<std::string> &args)
|
||||
{
|
||||
success_msg_writer() << "Here's your wallet's seed phrase. Write it down and keep in a safe place.";
|
||||
success_msg_writer(true) << "Anyone who knows the following 25 words can access you wallet:";
|
||||
success_msg_writer(true) << "Anyone who knows the following 25 words can access your wallet:";
|
||||
std::cout << m_wallet->get_account().get_restore_braindata() << std::endl << std::flush;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1269,7 +1324,7 @@ bool simple_wallet::show_seed(const std::vector<std::string> &args)
|
|||
bool simple_wallet::spendkey(const std::vector<std::string> &args)
|
||||
{
|
||||
message_writer(epee::log_space::console_color_red, true, std::string())
|
||||
<< "WARNING! Anyone who knows the following secret key can access you wallet and spend your coins.";
|
||||
<< "WARNING! Anyone who knows the following secret key can access your wallet and spend your coins.";
|
||||
|
||||
const account_keys& keys = m_wallet->get_account().get_keys();
|
||||
std::cout << "secret: " << epee::string_tools::pod_to_hex(keys.m_spend_secret_key) << std::endl;
|
||||
|
|
@ -1281,7 +1336,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args)
|
|||
bool simple_wallet::viewkey(const std::vector<std::string> &args)
|
||||
{
|
||||
message_writer(epee::log_space::console_color_yellow, false, std::string())
|
||||
<< "WARNING! Anyone who knows the following secret key can view you wallet (but can not spend your coins).";
|
||||
<< "WARNING! Anyone who knows the following secret key can view your wallet (but can not spend your coins).";
|
||||
|
||||
const account_keys& keys = m_wallet->get_account().get_keys();
|
||||
std::cout << "secret: " << epee::string_tools::pod_to_hex(keys.m_view_secret_key) << std::endl;
|
||||
|
|
@ -1512,6 +1567,94 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_below(const std::vector<std::string> &args)
|
||||
{
|
||||
bool r = false;
|
||||
if (args.size() < 3 || args.size() > 4)
|
||||
{
|
||||
fail_msg_writer() << "invalid agruments count: " << args.size() << ", expected 3 or 4";
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t fake_outs_count = 0;
|
||||
if (!string_tools::get_xtype_from_string(fake_outs_count, args[0]))
|
||||
{
|
||||
fail_msg_writer() << "mixin_count should be non-negative integer, got " << args[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
// parse payment_id
|
||||
currency::payment_id_t payment_id;
|
||||
if (args.size() == 4)
|
||||
{
|
||||
const std::string &payment_id_str = args.back();
|
||||
r = parse_payment_id_from_hex_str(payment_id_str, payment_id);
|
||||
if (!r)
|
||||
{
|
||||
fail_msg_writer() << "payment id has invalid format: \"" << payment_id_str << "\", expected hex string";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
currency::account_public_address addr;
|
||||
currency::payment_id_t integrated_payment_id;
|
||||
if (!m_wallet->get_transfer_address(args[1], addr, integrated_payment_id))
|
||||
{
|
||||
fail_msg_writer() << "wrong address: " << args[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
// handle integrated payment id
|
||||
if (!integrated_payment_id.empty())
|
||||
{
|
||||
if (!payment_id.empty())
|
||||
{
|
||||
fail_msg_writer() << "address " << args[1] << " has integrated payment id " << epee::string_tools::buff_to_hex_nodelimer(integrated_payment_id) <<
|
||||
" which is incompatible with payment id " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << " that was already assigned to this transfer";
|
||||
return true;
|
||||
}
|
||||
|
||||
payment_id = integrated_payment_id; // remember integrated payment id as the main payment id
|
||||
success_msg_writer() << "NOTE: using payment id " << epee::string_tools::buff_to_hex_nodelimer(payment_id) << " from integrated address " << args[1];
|
||||
}
|
||||
|
||||
uint64_t amount = 0;
|
||||
r = currency::parse_amount(amount, args[2]);
|
||||
if (!r || amount == 0)
|
||||
{
|
||||
fail_msg_writer() << "incorrect amount: " << args[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
uint64_t fee = m_wallet->get_core_runtime_config().tx_default_fee;
|
||||
size_t outs_total = 0, outs_swept = 0;
|
||||
uint64_t amount_total = 0, amount_swept = 0;
|
||||
currency::transaction result_tx = AUTO_VAL_INIT(result_tx);
|
||||
std::string filename = "zano_tx_unsigned";
|
||||
m_wallet->sweep_below(fake_outs_count, addr, amount, payment_id, fee, outs_total, amount_total, outs_swept, &result_tx, &filename);
|
||||
if (!get_inputs_money_amount(result_tx, amount_swept))
|
||||
LOG_ERROR("get_inputs_money_amount failed, tx: " << obj_to_json_str(result_tx));
|
||||
|
||||
success_msg_writer(false) << outs_swept << " outputs (" << print_money_brief(amount_swept) << " coins) of " << outs_total << " total (" << print_money_brief(amount_total)
|
||||
<< ") below the specified limit of " << print_money_brief(amount) << " were successfully swept";
|
||||
|
||||
if (m_wallet->is_watch_only())
|
||||
success_msg_writer(true) << "Transaction prepared for signing and saved into \"" << filename << "\" file, use full wallet to sign transfer and then use \"submit_transfer\" on this wallet to broadcast the transaction to the network";
|
||||
else
|
||||
success_msg_writer(true) << "tx: " << get_transaction_hash(result_tx) << " size: " << get_object_blobsize(result_tx) << " bytes";
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR(e.what());
|
||||
fail_msg_writer() << e.what();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
#ifdef WIN32
|
||||
int wmain( int argc, wchar_t* argv_w[ ], wchar_t* envp[ ] )
|
||||
#else
|
||||
|
|
@ -1563,6 +1706,7 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_dont_set_date);
|
||||
command_line::add_arg(desc_params, arg_print_brain_wallet);
|
||||
command_line::add_arg(desc_params, arg_do_pos_mining);
|
||||
command_line::add_arg(desc_params, arg_pos_mining_reward_address);
|
||||
command_line::add_arg(desc_params, arg_restore_wallet);
|
||||
command_line::add_arg(desc_params, arg_offline_mode);
|
||||
command_line::add_arg(desc_params, command_line::arg_log_file);
|
||||
|
|
@ -1713,6 +1857,17 @@ int main(int argc, char* argv[])
|
|||
break;
|
||||
}
|
||||
|
||||
currency::account_public_address miner_address = wal.get_account().get_public_address();
|
||||
if (command_line::has_arg(vm, arg_pos_mining_reward_address))
|
||||
{
|
||||
std::string arg_pos_mining_reward_address_str = command_line::get_arg(vm, arg_pos_mining_reward_address);
|
||||
if (!arg_pos_mining_reward_address_str.empty())
|
||||
{
|
||||
r = get_account_address_from_str(miner_address, arg_pos_mining_reward_address_str);
|
||||
CHECK_AND_ASSERT_MES(r, EXIT_FAILURE, "Failed to parse miner address from string: " << arg_pos_mining_reward_address_str);
|
||||
LOG_PRINT_YELLOW("PoS reward will be sent to another address: " << arg_pos_mining_reward_address_str, LOG_LEVEL_0);
|
||||
}
|
||||
}
|
||||
|
||||
tools::wallet_rpc_server wrpc(wal);
|
||||
bool r = wrpc.init(vm);
|
||||
|
|
@ -1722,7 +1877,7 @@ int main(int argc, char* argv[])
|
|||
wrpc.send_stop_signal();
|
||||
});
|
||||
LOG_PRINT_L0("Starting wallet rpc server");
|
||||
wrpc.run(command_line::get_arg(vm, arg_do_pos_mining), offline_mode);
|
||||
wrpc.run(command_line::get_arg(vm, arg_do_pos_mining), offline_mode, miner_address);
|
||||
LOG_PRINT_L0("Stopped wallet rpc server");
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ namespace currency
|
|||
bool refresh(const std::vector<std::string> &args);
|
||||
bool show_balance(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool list_recent_transfers(const std::vector<std::string>& args);
|
||||
bool list_recent_transfers_ex(const std::vector<std::string>& args);
|
||||
bool export_recent_transfers(const std::vector<std::string>& args);
|
||||
bool dump_trunsfers(const std::vector<std::string>& args);
|
||||
bool dump_key_images(const std::vector<std::string>& args);
|
||||
bool show_incoming_transfers(const std::vector<std::string> &args);
|
||||
|
|
@ -67,6 +67,7 @@ namespace currency
|
|||
bool fix_collisions(const std::vector<std::string> &args );
|
||||
bool scan_transfers_for_id(const std::vector<std::string> &args);
|
||||
bool scan_transfers_for_ki(const std::vector<std::string> &args);
|
||||
bool print_utxo_distribution(const std::vector<std::string> &args);
|
||||
bool show_blockchain_height(const std::vector<std::string> &args);
|
||||
bool show_wallet_bcheight(const std::vector<std::string> &args);
|
||||
bool transfer(const std::vector<std::string> &args);
|
||||
|
|
@ -83,6 +84,7 @@ namespace currency
|
|||
bool save_watch_only(const std::vector<std::string> &args);
|
||||
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 get_alias_from_daemon(const std::string& alias_name, currency::extra_alias_entry_base& ai);
|
||||
bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr);
|
||||
|
|
|
|||
|
|
@ -532,7 +532,7 @@ namespace
|
|||
r = m_p_core->handle_block_found(m_block_template, &bvc, false);
|
||||
if (r)
|
||||
{
|
||||
if (!bvc.m_verification_failed && !bvc.added_to_altchain && bvc.m_added_to_main_chain && !bvc.m_already_exists && !bvc.m_marked_as_orphaned)
|
||||
if (!bvc.m_verification_failed && !bvc.m_added_to_altchain && bvc.m_added_to_main_chain && !bvc.m_already_exists && !bvc.m_marked_as_orphaned)
|
||||
{
|
||||
LP_CC_WORKER_GREEN(p_ph->get_context(), "found block " << block_hash << " at height " << height << " was successfully added to the blockchain, difficulty " << m_network_difficulty, LOG_LEVEL_0);
|
||||
r = update_block_template();
|
||||
|
|
@ -544,7 +544,7 @@ namespace
|
|||
{
|
||||
LP_CC_WORKER_RED(p_ph->get_context(), "block " << block_hash << " at height " << height << " was NOT added to the blockchain:" << ENDL <<
|
||||
" verification_failed: " << bvc.m_verification_failed << ENDL <<
|
||||
" added_to_altchain: " << bvc.added_to_altchain << ENDL <<
|
||||
" added_to_altchain: " << bvc.m_added_to_altchain << ENDL <<
|
||||
" added_to_main_chain: " << bvc.m_added_to_main_chain << ENDL <<
|
||||
" already_exists: " << bvc.m_already_exists << ENDL <<
|
||||
" marked_as_orphaned: " << bvc.m_marked_as_orphaned, LOG_LEVEL_0);
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#define PROJECT_MAJOR_VERSION "1"
|
||||
#define PROJECT_MINOR_VERSION "1"
|
||||
#define PROJECT_REVISION "3"
|
||||
#define PROJECT_REVISION "4"
|
||||
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
|
||||
|
||||
#define PROJECT_VERSION_BUILD_NO 70
|
||||
#define PROJECT_VERSION_BUILD_NO 76
|
||||
#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 "]"
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@ namespace tools
|
|||
return invoke_http_json_rpc_update_is_disconnect("submitblock", req, rsp);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool default_http_core_proxy::call_COMMAND_RPC_SUBMITBLOCK2(const currency::COMMAND_RPC_SUBMITBLOCK2::request& req, currency::COMMAND_RPC_SUBMITBLOCK2::response& rsp)
|
||||
{
|
||||
return invoke_http_json_rpc_update_is_disconnect("submitblock2", req, rsp);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool default_http_core_proxy::check_connection()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace tools
|
|||
bool call_COMMAND_RPC_SCAN_POS(const currency::COMMAND_RPC_SCAN_POS::request& req, currency::COMMAND_RPC_SCAN_POS::response& rsp) override;
|
||||
bool call_COMMAND_RPC_GETBLOCKTEMPLATE(const currency::COMMAND_RPC_GETBLOCKTEMPLATE::request& req, currency::COMMAND_RPC_GETBLOCKTEMPLATE::response& rsp) override;
|
||||
bool call_COMMAND_RPC_SUBMITBLOCK(const currency::COMMAND_RPC_SUBMITBLOCK::request& req, currency::COMMAND_RPC_SUBMITBLOCK::response& rsp) override;
|
||||
bool call_COMMAND_RPC_SUBMITBLOCK2(const currency::COMMAND_RPC_SUBMITBLOCK2::request& req, currency::COMMAND_RPC_SUBMITBLOCK2::response& rsp) override;
|
||||
bool call_COMMAND_RPC_GET_POS_MINING_DETAILS(const currency::COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, currency::COMMAND_RPC_GET_POS_MINING_DETAILS::response& rsp) override;
|
||||
bool call_COMMAND_RPC_GET_BLOCKS_DETAILS(const currency::COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, currency::COMMAND_RPC_GET_BLOCKS_DETAILS::response& res) override;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ namespace tools
|
|||
virtual bool call_COMMAND_RPC_SCAN_POS(const currency::COMMAND_RPC_SCAN_POS::request& req, currency::COMMAND_RPC_SCAN_POS::response& rsp){ return false; }
|
||||
virtual bool call_COMMAND_RPC_GETBLOCKTEMPLATE(const currency::COMMAND_RPC_GETBLOCKTEMPLATE::request& req, currency::COMMAND_RPC_GETBLOCKTEMPLATE::response& rsp){ return false; }
|
||||
virtual bool call_COMMAND_RPC_SUBMITBLOCK(const currency::COMMAND_RPC_SUBMITBLOCK::request& req, currency::COMMAND_RPC_SUBMITBLOCK::response& rsp){ return false; }
|
||||
virtual bool call_COMMAND_RPC_SUBMITBLOCK2(const currency::COMMAND_RPC_SUBMITBLOCK2::request& req, currency::COMMAND_RPC_SUBMITBLOCK2::response& rsp) { return false; }
|
||||
virtual bool call_COMMAND_RPC_GET_POS_MINING_DETAILS(const currency::COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, currency::COMMAND_RPC_GET_POS_MINING_DETAILS::response& rsp){ return false; }
|
||||
virtual bool call_COMMAND_RPC_GET_BLOCKS_DETAILS(const currency::COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, currency::COMMAND_RPC_GET_BLOCKS_DETAILS::response& res){ return false; }
|
||||
virtual bool call_COMMAND_RPC_GET_OFFERS_EX(const currency::COMMAND_RPC_GET_OFFERS_EX::request& req, currency::COMMAND_RPC_GET_OFFERS_EX::response& res){ return false; }
|
||||
|
|
|
|||
|
|
@ -147,6 +147,11 @@ bool wallet2::set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::set_pos_mint_packing_size(uint64_t new_size)
|
||||
{
|
||||
m_pos_mint_packing_size = new_size;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::shared_ptr<i_core_proxy> wallet2::get_core_proxy()
|
||||
{
|
||||
return m_core_proxy;
|
||||
|
|
@ -385,7 +390,7 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
|
|||
if (coin_base_tx)
|
||||
{
|
||||
//last out in coinbase tx supposed to be change from coinstake
|
||||
if (!(i_in_outs == outs.size() - 1 && !is_derived_from_coinbase))
|
||||
if (!(o == tx.vout.size() - 1 && !is_derived_from_coinbase))
|
||||
{
|
||||
td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER;
|
||||
}
|
||||
|
|
@ -574,7 +579,17 @@ void wallet2::accept_proposal(const crypto::hash& contract_id, uint64_t b_accept
|
|||
finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
|
||||
prepare_transaction(construct_param, ftp, tx);
|
||||
mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been accepted with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">");
|
||||
finalize_transaction(ftp, tx, one_time_key, true);
|
||||
|
||||
try
|
||||
{
|
||||
finalize_transaction(ftp, tx, one_time_key, true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception in finalize_transaction, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(tx)));
|
||||
throw;
|
||||
}
|
||||
|
||||
print_tx_sent_message(tx, "(contract <" + epee::string_tools::pod_to_hex(contract_id) + ">)", construct_param.fee);
|
||||
|
||||
if (p_acceptance_tx != nullptr)
|
||||
|
|
@ -696,7 +711,16 @@ void wallet2::request_cancel_contract(const crypto::hash& contract_id, uint64_t
|
|||
currency::transaction tx = AUTO_VAL_INIT(tx);
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
mark_transfers_as_spent(ftp.selected_transfers, std::string("contract <") + epee::string_tools::pod_to_hex(contract_id) + "> has been requested for cancellaton with tx <" + epee::string_tools::pod_to_hex(get_transaction_hash(tx)) + ">");
|
||||
finalize_transaction(ftp, tx, sk, true);
|
||||
|
||||
try
|
||||
{
|
||||
finalize_transaction(ftp, tx, sk, true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception in finalize_transaction, tx: ") + epee::string_tools::pod_to_hex(get_transaction_hash(tx)));
|
||||
throw;
|
||||
}
|
||||
|
||||
print_tx_sent_message(tx, "(transport for cancel proposal)", fee);
|
||||
|
||||
|
|
@ -1111,7 +1135,9 @@ void wallet2::pull_blocks(size_t& blocks_added, std::atomic<bool>& stop)
|
|||
currency::COMMAND_RPC_GET_BLOCKS_DIRECT::response res = AUTO_VAL_INIT(res);
|
||||
get_short_chain_history(req.block_ids);
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_BLOCKS_DIRECT(req, res);
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::no_connection_to_daemon, "getblocks.bin");
|
||||
if (!r)
|
||||
throw error::no_connection_to_daemon(LOCATION_STR, "getblocks.bin");
|
||||
|
||||
if (res.status == CORE_RPC_STATUS_GENESIS_MISMATCH)
|
||||
{
|
||||
WLT_LOG_MAGENTA("Reseting genesis block...", LOG_LEVEL_0);
|
||||
|
|
@ -1293,12 +1319,11 @@ void wallet2::scan_tx_pool(bool& has_related_alias_in_unconfirmed)
|
|||
currency::COMMAND_RPC_GET_TX_POOL::response res = AUTO_VAL_INIT(res);
|
||||
bool r = m_core_proxy->call_COMMAND_RPC_GET_TX_POOL(req, res);
|
||||
if (res.status == CORE_RPC_STATUS_BUSY)
|
||||
throw error::daemon_busy("", "get_tx_pool");
|
||||
THROW_IF_TRUE_WALLET_EX(!r, error::no_connection_to_daemon, "get_tx_pool");
|
||||
THROW_IF_TRUE_WALLET_EX(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_tx_pool");
|
||||
throw error::daemon_busy(LOCATION_STR, "get_tx_pool");
|
||||
if (!r)
|
||||
throw error::no_connection_to_daemon(LOCATION_STR, "get_tx_pool");
|
||||
THROW_IF_TRUE_WALLET_EX(res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, res.status);
|
||||
|
||||
|
||||
|
||||
//- @#@ ----- debug
|
||||
#ifdef _DEBUG
|
||||
|
|
@ -1591,22 +1616,22 @@ void wallet2::refresh(size_t & blocks_fetched, bool& received_money, std::atomic
|
|||
if(!added_blocks)
|
||||
break;
|
||||
}
|
||||
catch (error::no_connection_to_daemon&)
|
||||
{
|
||||
blocks_fetched += added_blocks;
|
||||
if (++try_count > 3)
|
||||
return;
|
||||
WLT_LOG_L2("no connection to the daemon, wait and try pull_blocks again (try_count: " << try_count << ", blocks_fetched: " << blocks_fetched << ")");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
blocks_fetched += added_blocks;
|
||||
if(try_count < 3)
|
||||
{
|
||||
WLT_LOG_L1("Another try pull_blocks (try_count=" << try_count << "), exception: " << e.what());
|
||||
++try_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLT_LOG_ERROR("pull_blocks failed, try_count=" << try_count << ", exception: " << e.what());
|
||||
return;
|
||||
//throw;
|
||||
}
|
||||
WLT_LOG_ERROR("refresh->pull_blocks failed, try_count: " << try_count << ", blocks_fetched: " << blocks_fetched << ", exception: " << e.what());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(last_tx_hash_id != (m_transfers.size() ? get_transaction_hash(m_transfers.back().m_ptx_wallet_info->m_tx) : null_hash))
|
||||
received_money = true;
|
||||
|
||||
|
|
@ -1907,7 +1932,7 @@ void wallet2::load_keys2ki(bool create_if_not_exist, bool& need_to_resync)
|
|||
{
|
||||
WLT_LOG_RED("m_pending_key_images size: " << m_pending_key_images.size() << " is GREATER than m_pending_key_images_file_container size: " << m_pending_key_images_file_container.size(), LOG_LEVEL_0);
|
||||
WLT_LOG_RED("UNRECOVERABLE ERROR, wallet stops", LOG_LEVEL_0);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(false, "UNRECOVERABLE ERROR, wallet stops: m_pending_key_images > m_pending_key_images_file_container");
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(false, "UNRECOVERABLE ERROR, wallet stops: m_pending_key_images > m_pending_key_images_file_container" << ENDL << "Missing/wrong " << string_encoding::convert_to_ansii(m_pending_ki_file) << " file?");
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -2094,7 +2119,7 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor
|
|||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!data_file.fail(), "failed to open binary wallet file for saving: " << tmp_file_path.string());
|
||||
data_file << header_buff << keys_buff;
|
||||
|
||||
WLT_LOG_L0("Storing to " << tmp_file_path.string() << " ...");
|
||||
WLT_LOG_L0("Storing to temporary file " << tmp_file_path.string() << " ...");
|
||||
|
||||
r = tools::portble_serialize_obj_to_stream(*this, data_file);
|
||||
if (!r)
|
||||
|
|
@ -2107,15 +2132,39 @@ void wallet2::store(const std::wstring& path_to_save, const std::string& passwor
|
|||
data_file.flush();
|
||||
data_file.close();
|
||||
|
||||
WLT_LOG_L1("Stored successfully to temporary file " << tmp_file_path.string());
|
||||
|
||||
// for the sake of safety perform a double-renaming: wallet file -> old tmp, new tmp -> wallet file, remove old tmp
|
||||
|
||||
boost::filesystem::path tmp_old_file_path = boost::filesystem::path(path_to_save);
|
||||
tmp_old_file_path += L".oldtmp_" + std::to_wstring(ts);
|
||||
|
||||
if (boost::filesystem::is_regular_file(path_to_save))
|
||||
{
|
||||
boost::filesystem::rename(path_to_save, tmp_old_file_path);
|
||||
WLT_LOG_L1("Renamed: " << ascii_path_to_save << " -> " << tmp_old_file_path.string());
|
||||
}
|
||||
|
||||
boost::filesystem::rename(tmp_file_path, path_to_save);
|
||||
boost::filesystem::remove(tmp_old_file_path);
|
||||
WLT_LOG_L1("Renamed: " << tmp_file_path.string() << " -> " << ascii_path_to_save);
|
||||
|
||||
if (boost::filesystem::remove(tmp_old_file_path))
|
||||
{
|
||||
WLT_LOG_L1("Removed temporary file: " << tmp_old_file_path.string());
|
||||
}
|
||||
|
||||
bool path_to_save_exists = boost::filesystem::is_regular_file(path_to_save);
|
||||
bool tmp_file_path_exists = boost::filesystem::is_regular_file(tmp_file_path);
|
||||
bool tmp_old_file_path_exists = boost::filesystem::is_regular_file(tmp_old_file_path);
|
||||
if (path_to_save_exists && !tmp_file_path_exists && !tmp_old_file_path_exists)
|
||||
{
|
||||
WLT_LOG_L0("Wallet was successfully stored to " << ascii_path_to_save);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLT_LOG_ERROR("Wallet stroing to " << ascii_path_to_save << " might not be successfull: path_to_save_exists=" << path_to_save_exists << ", tmp_file_path_exists=" << tmp_file_path_exists << ", tmp_old_file_path_exists=" << tmp_old_file_path_exists);
|
||||
throw tools::error::wallet_common_error(LOCATION_STR, "Wallet file storing might not be successfull. Please make sure you have backed up your seed phrase and check log for details.");
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::store_watch_only(const std::wstring& path_to_save, const std::string& password) const
|
||||
|
|
@ -2271,6 +2320,36 @@ void wallet2::get_transfers(wallet2::transfer_container& incoming_transfers) con
|
|||
incoming_transfers = m_transfers;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number)
|
||||
{
|
||||
prepare_free_transfers_cache(0);
|
||||
auto it = m_found_free_amounts.find(CURRENCY_BLOCK_REWARD);
|
||||
if (it == m_found_free_amounts.end() || it->second.size() <= m_pos_mint_packing_size)
|
||||
return false;
|
||||
|
||||
//let's check if we have at least WALLET_POS_MINT_PACKING_SIZE transactions which is ready to go
|
||||
size_t count = 0;
|
||||
for (auto it_ind = it->second.begin(); it_ind != it->second.end() && count < m_pos_mint_packing_size; it_ind++)
|
||||
{
|
||||
if (is_transfer_ready_to_go(m_transfers[*it_ind], fake_outputs_number))
|
||||
++count;
|
||||
}
|
||||
if (count <= m_pos_mint_packing_size)
|
||||
return false;
|
||||
construct_tx_param ctp = get_default_construct_tx_param();
|
||||
currency::tx_destination_entry de = AUTO_VAL_INIT(de);
|
||||
de.addr.push_back(m_account.get_public_address());
|
||||
de.amount = m_pos_mint_packing_size*CURRENCY_BLOCK_REWARD;
|
||||
ctp.dsts.push_back(de);
|
||||
ctp.perform_packing = true;
|
||||
|
||||
TRY_ENTRY();
|
||||
transfer(ctp, tx, false, nullptr);
|
||||
CATCH_ENTRY2(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string wallet2::get_transfers_str(bool include_spent /*= true*/, bool include_unspent /*= true*/) const
|
||||
{
|
||||
static const char* header = "index amount g_index flags block tx out# key image";
|
||||
|
|
@ -2389,6 +2468,16 @@ void wallet2::sign_transfer_files(const std::string& tx_sources_file, const std:
|
|||
THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "failed to store signed tx to file " << signed_tx_file);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::get_utxo_distribution(std::map<uint64_t, uint64_t>& distribution)
|
||||
{
|
||||
prepare_free_transfers_cache(0);
|
||||
for (auto ent : m_found_free_amounts)
|
||||
{
|
||||
distribution[ent.first] = ent.second.size();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx)
|
||||
{
|
||||
// decrypt sources
|
||||
|
|
@ -2495,7 +2584,7 @@ uint64_t wallet2::get_recent_transfers_total_count()
|
|||
return m_transfer_history.size();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::get_recent_transfers_history(std::vector<wallet_public::wallet_transfer_info>& trs, size_t offset, size_t count)
|
||||
void wallet2::get_recent_transfers_history(std::vector<wallet_public::wallet_transfer_info>& trs, size_t offset, size_t count, uint64_t& total)
|
||||
{
|
||||
if (offset >= m_transfer_history.size())
|
||||
return;
|
||||
|
|
@ -2506,6 +2595,7 @@ void wallet2::get_recent_transfers_history(std::vector<wallet_public::wallet_tra
|
|||
stop = m_transfer_history.rend();
|
||||
|
||||
trs.insert(trs.end(), start, stop);
|
||||
total = m_transfer_history.size();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id)
|
||||
|
|
@ -2662,6 +2752,11 @@ bool wallet2::fill_mining_context(mining_context& ctx)
|
|||
}
|
||||
//------------------------------------------------------------------
|
||||
bool wallet2::try_mint_pos()
|
||||
{
|
||||
return try_mint_pos(m_account.get_public_address());
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool wallet2::try_mint_pos(const currency::account_public_address& miner_address)
|
||||
{
|
||||
mining_context ctx = AUTO_VAL_INIT(ctx);
|
||||
WLT_LOG_L1("Starting PoS mining iteration");
|
||||
|
|
@ -2690,7 +2785,7 @@ bool wallet2::try_mint_pos()
|
|||
|
||||
if (ctx.rsp.status == CORE_RPC_STATUS_OK)
|
||||
{
|
||||
build_minted_block(ctx.sp, ctx.rsp);
|
||||
build_minted_block(ctx.sp, ctx.rsp, miner_address);
|
||||
}
|
||||
|
||||
WLT_LOG_L0("PoS mining iteration finished, status: " << ctx.rsp.status << ", used " << ctx.sp.pos_entries.size() << " entries with total amount: " << print_money_brief(pos_entries_amount));
|
||||
|
|
@ -2738,6 +2833,13 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request&
|
|||
tmpl_req.pos_index = req.pos_entries[rsp.index].index;
|
||||
tmpl_req.extra_text = m_miner_text_info;
|
||||
tmpl_req.stake_unlock_time = req.pos_entries[rsp.index].stake_unlock_time;
|
||||
//generate packing tx
|
||||
transaction pack_tx = AUTO_VAL_INIT(pack_tx);
|
||||
if (generate_packing_transaction_if_needed(pack_tx, 0))
|
||||
{
|
||||
tx_to_blob(pack_tx, tmpl_req.explicit_transaction);
|
||||
WLT_LOG_GREEN("Pacling inputs: " << pack_tx.vin.size() << " inputs consolidated", LOG_LEVEL_0);
|
||||
}
|
||||
m_core_proxy->call_COMMAND_RPC_GETBLOCKTEMPLATE(tmpl_req, tmpl_rsp);
|
||||
WLT_CHECK_AND_ASSERT_MES(tmpl_rsp.status == CORE_RPC_STATUS_OK, false, "Failed to create block template after kernel hash found!");
|
||||
|
||||
|
|
@ -2781,10 +2883,13 @@ bool wallet2::build_minted_block(const currency::COMMAND_RPC_SCAN_POS::request&
|
|||
|
||||
WLT_LOG_GREEN("Block constructed <" << get_block_hash(b) << ">, sending to core...", LOG_LEVEL_0);
|
||||
|
||||
currency::COMMAND_RPC_SUBMITBLOCK::request subm_req = AUTO_VAL_INIT(subm_req);
|
||||
currency::COMMAND_RPC_SUBMITBLOCK::response subm_rsp = AUTO_VAL_INIT(subm_rsp);
|
||||
subm_req.push_back(epee::string_tools::buff_to_hex_nodelimer(t_serializable_object_to_blob(b)));
|
||||
m_core_proxy->call_COMMAND_RPC_SUBMITBLOCK(subm_req, subm_rsp);
|
||||
currency::COMMAND_RPC_SUBMITBLOCK2::request subm_req = AUTO_VAL_INIT(subm_req);
|
||||
currency::COMMAND_RPC_SUBMITBLOCK2::response subm_rsp = AUTO_VAL_INIT(subm_rsp);
|
||||
subm_req.b = t_serializable_object_to_blob(b);
|
||||
if (tmpl_req.explicit_transaction.size())
|
||||
subm_req.explicit_txs.push_back(hexemizer{ tmpl_req.explicit_transaction });
|
||||
|
||||
m_core_proxy->call_COMMAND_RPC_SUBMITBLOCK2(subm_req, subm_rsp);
|
||||
if (subm_rsp.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
WLT_LOG_ERROR("Constructed block is not accepted by core, status: " << subm_rsp.status);
|
||||
|
|
@ -3024,6 +3129,7 @@ void wallet2::dump_trunsfers(std::stringstream& ss, bool verbose) const
|
|||
}
|
||||
else
|
||||
{
|
||||
boost::io::ios_flags_saver ifs(ss);
|
||||
ss << "index amount spent_h g_index block block_ts flg tx out# key image" << ENDL;
|
||||
for (size_t i = 0; i != m_transfers.size(); i++)
|
||||
{
|
||||
|
|
@ -3068,39 +3174,6 @@ bool wallet2::get_contracts(escrow_contracts_container& contracts)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::get_fake_offers(std::list<bc_services::offer_details_ex>& offers, uint64_t amount)
|
||||
{
|
||||
|
||||
for (uint64_t i = 0; i != amount; i++)
|
||||
{
|
||||
bc_services::offer_details od;
|
||||
od.offer_type = rand() % 4;
|
||||
od.amount_primary = rand();
|
||||
od.amount_target = rand();
|
||||
od.bonus = get_random_rext(10);
|
||||
od.target = get_random_rext(10);
|
||||
od.location_country = get_random_rext(6);
|
||||
od.location_city = get_random_rext(10);
|
||||
od.contacts = get_random_rext(20);
|
||||
od.comment = get_random_rext(30);
|
||||
od.payment_types = get_random_rext(10);
|
||||
od.deal_option = get_random_rext(10);
|
||||
od.category = get_random_rext(4);
|
||||
od.expiration_time = 3;
|
||||
|
||||
crypto::hash tx_id = crypto::rand<crypto::hash>();
|
||||
offers.push_back(bc_services::offer_details_ex());
|
||||
bc_services::offer_details_ex& odl = offers.back();
|
||||
static_cast<bc_services::offer_details&>(odl) = od;
|
||||
odl.timestamp = m_core_runtime_config.get_core_time();
|
||||
odl.index_in_tx = 0;
|
||||
odl.tx_hash = tx_id;
|
||||
odl.stopped = false;
|
||||
odl.fee = 10000;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::build_escrow_release_templates(crypto::hash multisig_id,
|
||||
uint64_t fee,
|
||||
currency::transaction& tx_release_template,
|
||||
|
|
@ -3404,11 +3477,41 @@ void wallet2::send_escrow_proposal(const bc_services::contract_private_details&
|
|||
print_tx_sent_message(tx, "(from multisig)", fee);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
|
||||
{
|
||||
prepare_free_transfers_cache(fake_outputs_count);
|
||||
auto it = m_found_free_amounts.find(CURRENCY_BLOCK_REWARD);
|
||||
if (it == m_found_free_amounts.end() || it->second.size() < m_pos_mint_packing_size)
|
||||
return false;
|
||||
|
||||
for (auto set_it = it->second.begin(); set_it != it->second.end() && selected_indicies.size() <= m_pos_mint_packing_size; )
|
||||
{
|
||||
if (is_transfer_ready_to_go(m_transfers[*set_it], fake_outputs_count))
|
||||
{
|
||||
found_money += it->first;
|
||||
selected_indicies.push_back(*set_it);
|
||||
WLT_LOG_L2("Selected index: " << *set_it << ", transfer_details: " << ENDL << epee::serialization::store_t_to_json(m_transfers[*set_it]));
|
||||
|
||||
it->second.erase(set_it++);
|
||||
}
|
||||
else
|
||||
set_it++;
|
||||
}
|
||||
if (!it->second.size())
|
||||
m_found_free_amounts.erase(it);
|
||||
|
||||
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies, found_money);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::prepare_tx_sources(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
|
||||
{
|
||||
found_money = select_transfers(needed_money, fake_outputs_count, dust_threshold, selected_indicies);
|
||||
THROW_IF_FALSE_WALLET_EX_MES(found_money >= needed_money, error::not_enough_money, "wallet_dump: " << ENDL << dump_trunsfers(false), found_money, needed_money, 0);
|
||||
|
||||
return prepare_tx_sources(fake_outputs_count, sources, selected_indicies, found_money);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money)
|
||||
{
|
||||
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
|
||||
typedef currency::tx_source_entry::output_entry tx_output_entry;
|
||||
|
||||
|
|
@ -3571,17 +3674,18 @@ void wallet2::add_sent_tx_detailed_info(const transaction& tx,
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::mark_transfers_with_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason /* = empty_string */, bool throw_if_flag_already_set /* = false */)
|
||||
{
|
||||
if (throw_if_flag_already_set)
|
||||
{
|
||||
for (uint64_t i : selected_transfers)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(i < m_transfers.size(), "invalid transfer index given: " << i << ", m_transfers.size() == " << m_transfers.size());
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX((m_transfers[i].m_flags & flag) == 0, "transfer #" << i << " already has flag " << flag << ": " << m_transfers[i].m_flags << ", transfer info:" << ENDL << epee::serialization::store_t_to_json(m_transfers[i]));
|
||||
}
|
||||
}
|
||||
// check all selected transfers prior to flag change
|
||||
for (uint64_t i : selected_transfers)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(i < m_transfers.size(), "invalid transfer index given: " << i << ", m_transfers.size() == " << m_transfers.size());
|
||||
if (throw_if_flag_already_set)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX((m_transfers[i].m_flags & flag) == 0, "transfer #" << i << " already has flag " << flag << ": " << m_transfers[i].m_flags << ", transfer info:" << ENDL << epee::serialization::store_t_to_json(m_transfers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
for (uint64_t i : selected_transfers)
|
||||
{
|
||||
uint32_t flags_before = m_transfers[i].m_flags;
|
||||
m_transfers[i].m_flags |= flag;
|
||||
WLT_LOG_L1("marking transfer #" << std::setfill('0') << std::right << std::setw(3) << i << " with flag " << flag << " : " << flags_before << " -> " << m_transfers[i].m_flags <<
|
||||
|
|
@ -3589,16 +3693,22 @@ void wallet2::mark_transfers_with_flag(const std::vector<uint64_t>& selected_tra
|
|||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::clear_transfers_from_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason /* = empty_string */)
|
||||
void wallet2::clear_transfers_from_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason /* = empty_string */) noexcept
|
||||
{
|
||||
TRY_ENTRY();
|
||||
for (uint64_t i : selected_transfers)
|
||||
{
|
||||
THROW_IF_TRUE_WALLET_EX(i >= m_transfers.size(), error::wallet_internal_error, "i >= m_transfers.size()");
|
||||
if (i >= m_transfers.size())
|
||||
{
|
||||
WLT_LOG_ERROR("INTERNAL ERROR: i: " << i << " >= m_transfers.size() : " << m_transfers.size());
|
||||
continue;
|
||||
}
|
||||
uint32_t flags_before = m_transfers[i].m_flags;
|
||||
m_transfers[i].m_flags &= ~flag;
|
||||
WLT_LOG_L1("clearing transfer #" << std::setfill('0') << std::right << std::setw(3) << i << " from flag " << flag << " : " << flags_before << " -> " << m_transfers[i].m_flags <<
|
||||
(reason.empty() ? "" : ", reason: ") << reason);
|
||||
}
|
||||
CATCH_ENTRY_NO_RETURN();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::exception_handler()
|
||||
|
|
@ -4047,7 +4157,9 @@ void wallet2::prepare_transaction(const construct_tx_param& ctp, finalize_tx_par
|
|||
uint64_t found_money = 0;
|
||||
|
||||
TIME_MEASURE_START_MS(prepare_tx_sources_time);
|
||||
if (ctp.multisig_id == currency::null_hash)
|
||||
if (ctp.perform_packing)
|
||||
prepare_tx_sources_for_packing(WALLET_DEFAULT_POS_MINT_PACKING_SIZE, 0, ftp.sources, ftp.selected_transfers, found_money);
|
||||
else if (ctp.multisig_id == currency::null_hash)
|
||||
prepare_tx_sources(needed_money, ctp.fake_outputs_count, ctp.dust_policy.dust_threshold, ftp.sources, ftp.selected_transfers, found_money);
|
||||
else
|
||||
prepare_tx_sources(ctp.multisig_id, ftp.sources, found_money);
|
||||
|
|
@ -4069,6 +4181,7 @@ void wallet2::prepare_transaction(const construct_tx_param& ctp, finalize_tx_par
|
|||
ftp.shuffle = ctp.shuffle;
|
||||
ftp.flags = ctp.flags;
|
||||
ftp.multisig_id = ctp.multisig_id;
|
||||
ftp.spend_pub_key = m_account.get_public_address().m_spend_public_key;
|
||||
|
||||
/* TODO
|
||||
WLT_LOG_GREEN("[prepare_transaction]: get_needed_money_time: " << get_needed_money_time << " ms"
|
||||
|
|
@ -4079,12 +4192,15 @@ void wallet2::prepare_transaction(const construct_tx_param& ctp, finalize_tx_par
|
|||
LOG_LEVEL_0);*/
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::finalize_transaction(const finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx)
|
||||
void wallet2::finalize_transaction(const finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key /* = true */)
|
||||
{
|
||||
// NOTE: if broadcast_tx == true callback rise_on_transfer2() may be called at the end of this function.
|
||||
// That callback may call balance(), so it's important to have all used/spending transfers
|
||||
// to be correctly marked with corresponding flags PRIOR to calling finalize_transaction()
|
||||
|
||||
// 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");
|
||||
|
||||
//TIME_MEASURE_START_MS(construct_tx_time);
|
||||
bool r = currency::construct_tx(m_account.get_keys(),
|
||||
ftp.sources,
|
||||
|
|
@ -4116,10 +4232,11 @@ void wallet2::finalize_transaction(const finalize_tx_param& ftp, currency::trans
|
|||
}
|
||||
//TIME_MEASURE_FINISH_MS(sign_ms_input_time);
|
||||
|
||||
m_tx_keys.insert(std::make_pair(get_transaction_hash(tx), tx_key));
|
||||
|
||||
THROW_IF_FALSE_WALLET_EX(get_object_blobsize(tx) < CURRENCY_MAX_TRANSACTION_BLOB_SIZE, error::tx_too_big, tx, m_upper_transaction_size_limit);
|
||||
|
||||
if (store_tx_secret_key)
|
||||
m_tx_keys.insert(std::make_pair(get_transaction_hash(tx), tx_key));
|
||||
|
||||
//TIME_MEASURE_START(send_transaction_to_network_time);
|
||||
if (broadcast_tx)
|
||||
send_transaction_to_network(tx);
|
||||
|
|
@ -4161,7 +4278,7 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
|
|||
bool send_to_network,
|
||||
std::string* p_signed_tx_blob_str)
|
||||
{
|
||||
TIME_MEASURE_START(precalculation_time);
|
||||
//TIME_MEASURE_START(precalculation_time);
|
||||
construct_tx_param ctp = AUTO_VAL_INIT(ctp);
|
||||
ctp.attachments = attachments;
|
||||
ctp.crypt_address = currency::get_crypt_address_from_destinations(m_account.get_keys(), dsts);
|
||||
|
|
@ -4177,8 +4294,65 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
|
|||
ctp.split_strategy_id = destination_split_strategy_id;
|
||||
ctp.tx_outs_attr = tx_outs_attr;
|
||||
ctp.unlock_time = unlock_time;
|
||||
TIME_MEASURE_FINISH(precalculation_time);
|
||||
//TIME_MEASURE_FINISH(precalculation_time);
|
||||
transfer(ctp, tx, send_to_network, p_signed_tx_blob_str);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
construct_tx_param wallet2::get_default_construct_tx_param_inital()
|
||||
{
|
||||
construct_tx_param ctp = AUTO_VAL_INIT(ctp);
|
||||
|
||||
ctp.fee = m_core_runtime_config.tx_default_fee;
|
||||
ctp.dust_policy = tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD);
|
||||
ctp.split_strategy_id = tools::detail::ssi_digit;
|
||||
ctp.tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED;
|
||||
ctp.shuffle = 0;
|
||||
return ctp;
|
||||
}
|
||||
const construct_tx_param& wallet2::get_default_construct_tx_param()
|
||||
{
|
||||
static construct_tx_param ctp = get_default_construct_tx_param_inital();
|
||||
return ctp;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::store_unsigned_tx_to_file_and_reserve_transfers(const finalize_tx_param& ftp, const std::string& filename, std::string* p_unsigned_tx_blob_str /* = nullptr */)
|
||||
{
|
||||
TIME_MEASURE_START(store_unsigned_tx_time);
|
||||
blobdata bl = t_serializable_object_to_blob(ftp);
|
||||
crypto::chacha_crypt(bl, m_account.get_keys().m_view_secret_key);
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
bool r = epee::file_io_utils::save_string_to_file(filename, bl);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to store unsigned tx to " << filename);
|
||||
LOG_PRINT_L0("Transaction stored to " << filename << ". You need to sign this tx using a full-access wallet.");
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(p_unsigned_tx_blob_str != nullptr, false, "empty filename and p_unsigned_tx_blob_str == null");
|
||||
*p_unsigned_tx_blob_str = bl;
|
||||
}
|
||||
|
||||
TIME_MEASURE_FINISH(store_unsigned_tx_time);
|
||||
|
||||
// reserve transfers at the very end
|
||||
TIME_MEASURE_START(mark_transfers_as_spent_time);
|
||||
mark_transfers_with_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION, std::string("cold sig reservation for money transfer"), true);
|
||||
TIME_MEASURE_FINISH(mark_transfers_as_spent_time);
|
||||
|
||||
WLT_LOG_GREEN("[wallet::store_unsigned_tx_to_file_and_reserve_transfers]"
|
||||
<< " store_unsigned_tx_time: " << print_fixed_decimal_point(store_unsigned_tx_time, 3)
|
||||
<< ", mark_transfers_as_spent_time: " << print_fixed_decimal_point(mark_transfers_as_spent_time, 3)
|
||||
, LOG_LEVEL_1);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::transfer(const construct_tx_param& ctp,
|
||||
currency::transaction &tx,
|
||||
bool send_to_network,
|
||||
std::string* p_signed_tx_blob_str)
|
||||
{
|
||||
TIME_MEASURE_START(prepare_transaction_time);
|
||||
finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
|
||||
prepare_transaction(ctp, ftp);
|
||||
|
|
@ -4186,29 +4360,9 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
|
|||
|
||||
if (m_watch_only)
|
||||
{
|
||||
TIME_MEASURE_START(store_unsigned_tx_time);
|
||||
ftp.spend_pub_key = m_account.get_public_address().m_spend_public_key;
|
||||
blobdata bl = t_serializable_object_to_blob(ftp);
|
||||
crypto::chacha_crypt(bl, m_account.get_keys().m_view_secret_key);
|
||||
epee::file_io_utils::save_string_to_file("zano_tx_unsigned", bl);
|
||||
LOG_PRINT_L0("Transaction stored to unsigned_zano_tx. You need to sign this tx using a full-access wallet.");
|
||||
|
||||
if (p_signed_tx_blob_str != nullptr)
|
||||
*p_signed_tx_blob_str = bl;
|
||||
TIME_MEASURE_FINISH(store_unsigned_tx_time);
|
||||
|
||||
// unlock transfers at the very end
|
||||
TIME_MEASURE_START(mark_transfers_as_spent_time);
|
||||
mark_transfers_with_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_COLD_SIG_RESERVATION, std::string("cold sig reservation for money transfer"), true);
|
||||
TIME_MEASURE_FINISH(mark_transfers_as_spent_time);
|
||||
|
||||
WLT_LOG_GREEN("[wallet::transfer]"
|
||||
<< " precalculation_time: " << print_fixed_decimal_point(precalculation_time, 3)
|
||||
<< ", prepare_transaction_time: " << print_fixed_decimal_point(prepare_transaction_time, 3)
|
||||
<< ", store_unsigned_tx_time: " << print_fixed_decimal_point(store_unsigned_tx_time, 3)
|
||||
<< ", mark_transfers_as_spent_time: " << print_fixed_decimal_point(mark_transfers_as_spent_time, 3)
|
||||
, LOG_LEVEL_0);
|
||||
|
||||
bool r = store_unsigned_tx_to_file_and_reserve_transfers(ftp, "zano_tx_unsigned", p_signed_tx_blob_str);
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "failed to store unsigned tx");
|
||||
WLT_LOG_GREEN("[wallet::transfer]" << " prepare_transaction_time: " << print_fixed_decimal_point(prepare_transaction_time, 3), LOG_LEVEL_0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4231,14 +4385,268 @@ void wallet2::transfer(const std::vector<currency::tx_destination_entry>& dsts,
|
|||
|
||||
|
||||
WLT_LOG_GREEN("[wallet::transfer]"
|
||||
<< " precalculation_time: " << print_fixed_decimal_point(precalculation_time, 3)
|
||||
//<< " precalculation_time: " << print_fixed_decimal_point(precalculation_time, 3)
|
||||
<< ", prepare_transaction_time: " << print_fixed_decimal_point(prepare_transaction_time, 3)
|
||||
<< ", finalize_transaction_time: " << print_fixed_decimal_point(finalize_transaction_time, 3)
|
||||
<< ", mark_transfers_as_spent_time: " << print_fixed_decimal_point(mark_transfers_as_spent_time, 3)
|
||||
, LOG_LEVEL_0);
|
||||
|
||||
print_tx_sent_message(tx, std::string() + "(transfer)", fee);
|
||||
print_tx_sent_message(tx, std::string() + "(transfer)", ctp.fee);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::sweep_below(size_t fake_outs_count, const currency::account_public_address& destination_addr, uint64_t threshold_amount, const currency::payment_id_t& payment_id,
|
||||
uint64_t fee, size_t& outs_total, uint64_t& amount_total, size_t& outs_swept, currency::transaction* p_result_tx /* = nullptr */, std::string* p_filename_or_unsigned_tx_blob_str /* = nullptr */)
|
||||
{
|
||||
static const size_t estimated_bytes_per_input = 78;
|
||||
const size_t estimated_max_inputs = static_cast<size_t>(CURRENCY_MAX_TRANSACTION_BLOB_SIZE / (estimated_bytes_per_input * (fake_outs_count + 1.5))); // estimated number of maximum tx inputs under the tx size limit
|
||||
const size_t tx_sources_for_querying_random_outs_max = estimated_max_inputs * 2;
|
||||
|
||||
bool r = false;
|
||||
outs_total = 0;
|
||||
amount_total = 0;
|
||||
outs_swept = 0;
|
||||
|
||||
std::vector<size_t> selected_transfers;
|
||||
selected_transfers.reserve(m_transfers.size());
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
uint64_t amount = td.amount();
|
||||
if (amount < threshold_amount &&
|
||||
is_transfer_ready_to_go(td, fake_outs_count))
|
||||
{
|
||||
selected_transfers.push_back(i);
|
||||
outs_total += 1;
|
||||
amount_total += amount;
|
||||
}
|
||||
}
|
||||
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(!selected_transfers.empty(), "No spendable outputs meet the criterion");
|
||||
|
||||
// sort by amount descending in order to spend bigger outputs first
|
||||
std::sort(selected_transfers.begin(), selected_transfers.end(), [this](size_t a, size_t b) { return m_transfers[b].amount() < m_transfers[a].amount(); });
|
||||
|
||||
// limit RPC request with reasonable number of sources
|
||||
if (selected_transfers.size() > tx_sources_for_querying_random_outs_max)
|
||||
selected_transfers.erase(selected_transfers.begin() + tx_sources_for_querying_random_outs_max, selected_transfers.end());
|
||||
|
||||
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
|
||||
typedef currency::tx_source_entry::output_entry tx_output_entry;
|
||||
|
||||
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response rpc_get_random_outs_resp = AUTO_VAL_INIT(rpc_get_random_outs_resp);
|
||||
if (fake_outs_count > 0)
|
||||
{
|
||||
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
|
||||
req.use_forced_mix_outs = false;
|
||||
req.outs_count = fake_outs_count + 1;
|
||||
for (size_t i : selected_transfers)
|
||||
req.amounts.push_back(m_transfers[i].amount());
|
||||
|
||||
r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, rpc_get_random_outs_resp);
|
||||
|
||||
THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs.bin");
|
||||
THROW_IF_FALSE_WALLET_EX(rpc_get_random_outs_resp.status != CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin");
|
||||
THROW_IF_FALSE_WALLET_EX(rpc_get_random_outs_resp.status == CORE_RPC_STATUS_OK, error::get_random_outs_error, rpc_get_random_outs_resp.status);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(rpc_get_random_outs_resp.outs.size() == selected_transfers.size(),
|
||||
"daemon returned wrong number of amounts for getrandom_outs.bin: " << rpc_get_random_outs_resp.outs.size() << ", requested: " << selected_transfers.size());
|
||||
|
||||
std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs;
|
||||
for (COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs : rpc_get_random_outs_resp.outs)
|
||||
{
|
||||
if (amount_outs.outs.size() < fake_outs_count)
|
||||
scanty_outs.push_back(amount_outs);
|
||||
}
|
||||
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outs_count);
|
||||
}
|
||||
|
||||
finalize_tx_param ftp = AUTO_VAL_INIT(ftp);
|
||||
if (!payment_id.empty())
|
||||
set_payment_id_to_tx(ftp.attachments, payment_id);
|
||||
// put encrypted payer info into the extra
|
||||
ftp.crypt_address = destination_addr;
|
||||
currency::tx_payer txp = AUTO_VAL_INIT(txp);
|
||||
txp.acc_addr = m_account.get_public_address();
|
||||
ftp.extra.push_back(txp);
|
||||
ftp.flags = 0;
|
||||
// ftp.multisig_id -- not required
|
||||
// ftp.prepared_destinations -- will be filled by prepare_tx_destinations
|
||||
// ftp.selected_transfers -- needed only at stage of broadcasting or storing unsigned tx
|
||||
ftp.shuffle = false;
|
||||
// ftp.sources -- will be filled in try_construct_tx
|
||||
ftp.spend_pub_key = m_account.get_public_address().m_spend_public_key; // needed for offline signing
|
||||
ftp.tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED;
|
||||
ftp.unlock_time = 0;
|
||||
|
||||
enum try_construct_result_t {rc_ok = 0, rc_too_few_outputs = 1, rc_too_many_outputs = 2, rc_create_tx_failed = 3 };
|
||||
auto get_result_t_str = [](try_construct_result_t t) -> const char*
|
||||
{ return t == rc_ok ? "rc_ok" : t == rc_too_few_outputs ? "rc_too_few_outputs" : t == rc_too_many_outputs ? "rc_too_many_outputs" : t == rc_create_tx_failed ? "rc_create_tx_failed" : "unknown"; };
|
||||
|
||||
auto try_construct_tx = [this, &selected_transfers, &rpc_get_random_outs_resp, &fake_outs_count, &fee, &destination_addr]
|
||||
(size_t st_index_upper_boundary, finalize_tx_param& ftp, uint64_t& amount_swept) -> try_construct_result_t
|
||||
{
|
||||
// prepare inputs
|
||||
amount_swept = 0;
|
||||
ftp.sources.clear();
|
||||
ftp.sources.resize(st_index_upper_boundary);
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(st_index_upper_boundary <= selected_transfers.size(), "index_upper_boundary = " << st_index_upper_boundary << ", selected_transfers.size() = " << selected_transfers.size());
|
||||
for (size_t st_index = 0; st_index < st_index_upper_boundary; ++st_index)
|
||||
{
|
||||
currency::tx_source_entry& src = ftp.sources[st_index];
|
||||
size_t tr_index = selected_transfers[st_index];
|
||||
transfer_details& td = m_transfers[tr_index];
|
||||
src.transfer_index = tr_index;
|
||||
src.amount = td.amount();
|
||||
amount_swept += src.amount;
|
||||
|
||||
// populate src.outputs with mix-ins
|
||||
if (rpc_get_random_outs_resp.outs.size())
|
||||
{
|
||||
rpc_get_random_outs_resp.outs[st_index].outs.sort([](const out_entry& a, const out_entry& b) { return a.global_amount_index < b.global_amount_index; });
|
||||
for (out_entry& daemon_oe : rpc_get_random_outs_resp.outs[st_index].outs)
|
||||
{
|
||||
if (td.m_global_output_index == daemon_oe.global_amount_index)
|
||||
continue;
|
||||
tx_output_entry oe;
|
||||
oe.first = daemon_oe.global_amount_index;
|
||||
oe.second = daemon_oe.out_key;
|
||||
src.outputs.push_back(oe);
|
||||
if (src.outputs.size() >= fake_outs_count)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// insert real output into src.outputs
|
||||
auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a)
|
||||
{
|
||||
if (a.first.type().hash_code() == typeid(uint64_t).hash_code())
|
||||
return boost::get<uint64_t>(a.first) >= td.m_global_output_index;
|
||||
return false; // TODO: implement deterministics real output placement in case there're ref_by_id outs
|
||||
});
|
||||
tx_output_entry real_oe;
|
||||
real_oe.first = td.m_global_output_index;
|
||||
real_oe.second = boost::get<txout_to_key>(td.m_ptx_wallet_info->m_tx.vout[td.m_internal_output_index].target).key;
|
||||
auto inserted_it = src.outputs.insert(it_to_insert, real_oe);
|
||||
src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_ptx_wallet_info->m_tx);
|
||||
src.real_output = inserted_it - src.outputs.begin();
|
||||
src.real_output_in_tx_index = td.m_internal_output_index;
|
||||
//detail::print_source_entry(src);
|
||||
}
|
||||
|
||||
if (amount_swept <= fee)
|
||||
return rc_too_few_outputs;
|
||||
|
||||
// try to construct a transaction
|
||||
std::vector<currency::tx_destination_entry> dsts({ tx_destination_entry(amount_swept - fee, destination_addr) });
|
||||
prepare_tx_destinations(0, 0, detail::ssi_digit, tools::tx_dust_policy(), dsts, ftp.prepared_destinations);
|
||||
|
||||
currency::transaction tx = AUTO_VAL_INIT(tx);
|
||||
crypto::secret_key tx_key = AUTO_VAL_INIT(tx_key);
|
||||
try
|
||||
{
|
||||
finalize_transaction(ftp, tx, tx_key, false, false);
|
||||
}
|
||||
catch (error::tx_too_big)
|
||||
{
|
||||
return rc_too_many_outputs;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return rc_create_tx_failed;
|
||||
}
|
||||
|
||||
return rc_ok;
|
||||
};
|
||||
|
||||
size_t st_index_upper_boundary = std::min(selected_transfers.size(), estimated_max_inputs);
|
||||
uint64_t amount_swept = 0;
|
||||
try_construct_result_t res = try_construct_tx(st_index_upper_boundary, ftp, amount_swept);
|
||||
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(res != rc_too_few_outputs, st_index_upper_boundary << " biggest unspent outputs have total amount of " << print_money_brief(amount_swept)
|
||||
<< " which is less than required fee: " << print_money_brief(fee) << ", transaction cannot be constructed");
|
||||
|
||||
if (res == rc_too_many_outputs)
|
||||
{
|
||||
WLT_LOG_L1("sweep_below: first try of try_construct_tx(" << st_index_upper_boundary << ") returned " << get_result_t_str(res));
|
||||
size_t low_bound = 0;
|
||||
size_t high_bound = st_index_upper_boundary;
|
||||
finalize_tx_param ftp_ok = ftp;
|
||||
for (;;)
|
||||
{
|
||||
if (low_bound + 1 >= high_bound)
|
||||
{
|
||||
st_index_upper_boundary = low_bound;
|
||||
res = rc_ok;
|
||||
ftp = ftp_ok;
|
||||
break;
|
||||
}
|
||||
st_index_upper_boundary = (low_bound + high_bound) / 2;
|
||||
try_construct_result_t res = try_construct_tx(st_index_upper_boundary, ftp, amount_swept);
|
||||
WLT_LOG_L1("sweep_below: try_construct_tx(" << st_index_upper_boundary << ") returned " << get_result_t_str(res));
|
||||
if (res == rc_ok)
|
||||
{
|
||||
low_bound = st_index_upper_boundary;
|
||||
ftp_ok = ftp;
|
||||
}
|
||||
else if (res == rc_too_many_outputs)
|
||||
{
|
||||
high_bound = st_index_upper_boundary;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != rc_ok)
|
||||
{
|
||||
uint64_t amount_min = UINT64_MAX, amount_max = 0, amount_sum = 0;
|
||||
for (auto& i : selected_transfers)
|
||||
{
|
||||
uint64_t amount = m_transfers[i].amount();
|
||||
amount_min = std::min(amount_min, amount);
|
||||
amount_max = std::max(amount_max, amount);
|
||||
amount_sum += amount;
|
||||
}
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(false, "try_construct_tx failed with result: " << get_result_t_str(res) << " (" << res << ")" <<
|
||||
", selected_transfers stats:\n" <<
|
||||
" outs: " << selected_transfers.size() << ENDL <<
|
||||
" amount min: " << print_money(amount_min) << ENDL <<
|
||||
" amount max: " << print_money(amount_max) << ENDL <<
|
||||
" amount avg: " << (selected_transfers.empty() ? std::string("n/a") : print_money(amount_sum / selected_transfers.size())));
|
||||
}
|
||||
|
||||
// populate ftp.selected_transfers from ftp.sources
|
||||
ftp.selected_transfers.clear();
|
||||
for (size_t i = 0; i < ftp.sources.size(); ++i)
|
||||
ftp.selected_transfers.push_back(ftp.sources[i].transfer_index);
|
||||
|
||||
outs_swept = ftp.sources.size();
|
||||
|
||||
|
||||
if (m_watch_only)
|
||||
{
|
||||
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(p_filename_or_unsigned_tx_blob_str != nullptr, "p_filename_or_unsigned_tx_blob_str is null");
|
||||
bool r = store_unsigned_tx_to_file_and_reserve_transfers(ftp, *p_filename_or_unsigned_tx_blob_str, p_filename_or_unsigned_tx_blob_str);
|
||||
WLT_THROW_IF_FALSE_WALLET_CMN_ERR_EX(r, "failed to store unsigned tx");
|
||||
return;
|
||||
}
|
||||
|
||||
mark_transfers_as_spent(ftp.selected_transfers, "sweep_below");
|
||||
|
||||
transaction local_tx;
|
||||
transaction* p_tx = p_result_tx != nullptr ? p_result_tx : &local_tx;
|
||||
*p_tx = AUTO_VAL_INIT_T(transaction);
|
||||
try
|
||||
{
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
finalize_transaction(ftp, *p_tx, sk, true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
clear_transfers_from_flag(ftp.selected_transfers, WALLET_TRANSFER_DETAIL_FLAG_SPENT, std::string("exception on sweep_below, tx id (might be wrong): ") + epee::string_tools::pod_to_hex(get_transaction_hash(*p_tx)));
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace tools
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
#define WALLET_DEFAULT_TX_SPENDABLE_AGE 10
|
||||
#define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1
|
||||
|
||||
#define WALLET_DEFAULT_POS_MINT_PACKING_SIZE 100
|
||||
|
||||
#undef LOG_DEFAULT_CHANNEL
|
||||
#define LOG_DEFAULT_CHANNEL "wallet"
|
||||
ENABLE_CHANNEL_BY_DEFAULT("wallet");
|
||||
|
|
@ -256,6 +258,7 @@ namespace tools
|
|||
currency::account_public_address crypt_address;
|
||||
uint8_t tx_outs_attr;
|
||||
bool shuffle;
|
||||
bool perform_packing;
|
||||
};
|
||||
|
||||
struct finalize_tx_param
|
||||
|
|
@ -313,7 +316,8 @@ namespace tools
|
|||
m_last_sync_percent(0),
|
||||
m_do_rise_transfer(false),
|
||||
m_watch_only(false),
|
||||
m_last_pow_block_h(0)
|
||||
m_last_pow_block_h(0),
|
||||
m_pos_mint_packing_size(WALLET_DEFAULT_POS_MINT_PACKING_SIZE)
|
||||
{};
|
||||
public:
|
||||
wallet2() : m_stop(false),
|
||||
|
|
@ -326,7 +330,8 @@ namespace tools
|
|||
m_do_rise_transfer(false),
|
||||
m_log_prefix("???"),
|
||||
m_watch_only(false),
|
||||
m_last_pow_block_h(0)
|
||||
m_last_pow_block_h(0),
|
||||
m_pos_mint_packing_size(WALLET_DEFAULT_POS_MINT_PACKING_SIZE)
|
||||
{
|
||||
m_core_runtime_config = currency::get_default_core_runtime_config();
|
||||
};
|
||||
|
|
@ -459,7 +464,7 @@ namespace tools
|
|||
currency::account_base& get_account() { return m_account; }
|
||||
const currency::account_base& get_account() const { return m_account; }
|
||||
|
||||
void get_recent_transfers_history(std::vector<wallet_public::wallet_transfer_info>& trs, size_t offset, size_t count);
|
||||
void get_recent_transfers_history(std::vector<wallet_public::wallet_transfer_info>& trs, size_t offset, size_t count, uint64_t& total);
|
||||
uint64_t get_recent_transfers_total_count();
|
||||
void get_unconfirmed_transfers(std::vector<wallet_public::wallet_transfer_info>& trs);
|
||||
void init(const std::string& daemon_address = "http://localhost:8080");
|
||||
|
|
@ -491,6 +496,7 @@ namespace tools
|
|||
|
||||
|
||||
bool set_core_proxy(const std::shared_ptr<i_core_proxy>& proxy);
|
||||
void set_pos_mint_packing_size(uint64_t new_size);
|
||||
std::shared_ptr<i_core_proxy> get_core_proxy();
|
||||
uint64_t balance() const;
|
||||
uint64_t balance(uint64_t& unloked, uint64_t& awaiting_in, uint64_t& awaiting_out, uint64_t& mined) const;
|
||||
|
|
@ -538,6 +544,11 @@ namespace tools
|
|||
const std::vector<currency::attachment_v>& attachments,
|
||||
currency::transaction& tx);
|
||||
|
||||
void transfer(const construct_tx_param& ctp,
|
||||
currency::transaction &tx,
|
||||
bool send_to_network,
|
||||
std::string* p_signed_tx_blob_str);
|
||||
|
||||
template<typename destination_split_strategy_t>
|
||||
void transfer_from_contract(
|
||||
const std::list<currency::account_keys>& owner_keys,
|
||||
|
|
@ -611,6 +622,9 @@ namespace tools
|
|||
void submit_transfer(const std::string& signed_tx_blob, currency::transaction& tx);
|
||||
void submit_transfer_files(const std::string& signed_tx_file, currency::transaction& tx);
|
||||
|
||||
void sweep_below(size_t fake_outs_count, const currency::account_public_address& destination_addr, uint64_t threshold_amount, const currency::payment_id_t& payment_id,
|
||||
uint64_t fee, size_t& outs_total, uint64_t& amount_total, size_t& outs_swept, currency::transaction* p_result_tx = nullptr, std::string* p_filename_or_unsigned_tx_blob_str = nullptr);
|
||||
|
||||
bool get_transfer_address(const std::string& adr_str, currency::account_public_address& addr, std::string& payment_id);
|
||||
uint64_t get_blockchain_current_height() const { return m_blockchain.size(); }
|
||||
|
||||
|
|
@ -670,6 +684,7 @@ namespace tools
|
|||
//PoS
|
||||
//synchronous version of function
|
||||
bool try_mint_pos();
|
||||
bool try_mint_pos(const currency::account_public_address& miner_address); // block reward will be sent to miner_address, stake will be returned back to the wallet
|
||||
//for unit tests
|
||||
friend class ::test_generator;
|
||||
|
||||
|
|
@ -698,7 +713,6 @@ namespace tools
|
|||
bool reset_password(const std::string& pass);
|
||||
bool is_password_valid(const std::string& pass);
|
||||
bool get_actual_offers(std::list<bc_services::offer_details_ex>& offers);
|
||||
bool get_fake_offers(std::list<bc_services::offer_details_ex>& offers, uint64_t amount);
|
||||
bool process_contract_info(wallet_public::wallet_transfer_info& wti, const std::vector<currency::payload_items_v>& decrypted_attach);
|
||||
bool handle_proposal(wallet_public::wallet_transfer_info& wti, const bc_services::proposal_body& prop);
|
||||
void accept_proposal(const crypto::hash& contract_id, uint64_t b_acceptance_fee, currency::transaction* p_acceptance_tx = nullptr);
|
||||
|
|
@ -725,10 +739,11 @@ namespace tools
|
|||
bool get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key) const;
|
||||
|
||||
void prepare_transaction(const construct_tx_param& ctp, finalize_tx_param& ftp, const currency::transaction& tx_for_mode_separate = currency::transaction());
|
||||
void finalize_transaction(const finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx);
|
||||
void finalize_transaction(const finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key = true);
|
||||
|
||||
std::string get_log_prefix() const { return m_log_prefix; }
|
||||
static uint64_t get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td);
|
||||
bool get_utxo_distribution(std::map<uint64_t, uint64_t>& distribution);
|
||||
|
||||
private:
|
||||
void add_transfers_to_expiration_list(const std::vector<uint64_t>& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id);
|
||||
|
|
@ -784,7 +799,9 @@ private:
|
|||
void process_genesis_if_needed(const currency::block& genesis);
|
||||
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(uint64_t needed_money, size_t fake_outputs_count, uint64_t dust_threshold, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
|
||||
bool prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
|
||||
bool prepare_tx_sources(crypto::hash multisig_id, std::vector<currency::tx_source_entry>& sources, uint64_t& found_money);
|
||||
bool prepare_tx_sources_for_packing(uint64_t items_to_pack, size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, std::vector<uint64_t>& selected_indicies, uint64_t& found_money);
|
||||
uint64_t get_needed_money(uint64_t fee, const std::vector<currency::tx_destination_entry>& dsts);
|
||||
void prepare_tx_destinations(uint64_t needed_money,
|
||||
uint64_t found_money,
|
||||
|
|
@ -800,7 +817,9 @@ private:
|
|||
|
||||
void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const wallet_public::wallet_transfer_info& wti) const;
|
||||
void change_contract_state(wallet_public::escrow_contract_details_basic& contract, uint32_t new_state, const crypto::hash& contract_id, const std::string& reason = "internal intention") const;
|
||||
|
||||
|
||||
construct_tx_param get_default_construct_tx_param_inital();
|
||||
const construct_tx_param& get_default_construct_tx_param();
|
||||
|
||||
uint64_t get_tx_expiration_median() const;
|
||||
|
||||
|
|
@ -837,12 +856,13 @@ private:
|
|||
const std::vector<uint64_t>& selected_indicies);
|
||||
void mark_transfers_as_spent(const std::vector<uint64_t>& selected_transfers, const std::string& reason = std::string());
|
||||
void mark_transfers_with_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason = std::string(), bool throw_if_flag_already_set = false);
|
||||
void clear_transfers_from_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason = std::string());
|
||||
void clear_transfers_from_flag(const std::vector<uint64_t>& selected_transfers, uint32_t flag, const std::string& reason = std::string()) noexcept;
|
||||
void exception_handler();
|
||||
void exception_handler() const;
|
||||
uint64_t get_minimum_allowed_fee_for_contract(const crypto::hash& ms_id);
|
||||
void check_for_free_space_and_throw_if_it_lacks(const std::wstring& path, uint64_t exact_size_needed_if_known = UINT64_MAX);
|
||||
|
||||
bool generate_packing_transaction_if_needed(currency::transaction& tx, uint64_t fake_outputs_number);
|
||||
bool store_unsigned_tx_to_file_and_reserve_transfers(const finalize_tx_param& ftp, const std::string& filename, std::string* p_unsigned_tx_blob_str = nullptr);
|
||||
|
||||
|
||||
currency::account_base m_account;
|
||||
|
|
@ -855,6 +875,7 @@ private:
|
|||
std::atomic<uint64_t> m_local_bc_height; //temporary workaround
|
||||
std::atomic<uint64_t> m_last_bc_timestamp;
|
||||
bool m_do_rise_transfer;
|
||||
uint64_t m_pos_mint_packing_size;
|
||||
|
||||
transfer_container m_transfers;
|
||||
multisig_transfer_container m_multisig_transfers;
|
||||
|
|
|
|||
|
|
@ -375,6 +375,45 @@ namespace wallet_public
|
|||
};
|
||||
};
|
||||
|
||||
struct COMMAND_SWEEP_BELOW
|
||||
{
|
||||
struct request
|
||||
{
|
||||
uint64_t mixin;
|
||||
std::string address;
|
||||
uint64_t amount;
|
||||
std::string payment_id_hex;
|
||||
uint64_t fee;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(mixin)
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(amount)
|
||||
KV_SERIALIZE(payment_id_hex)
|
||||
KV_SERIALIZE(fee)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string tx_hash;
|
||||
std::string tx_unsigned_hex;
|
||||
uint64_t outs_total;
|
||||
uint64_t amount_total;
|
||||
uint64_t outs_swept;
|
||||
uint64_t amount_swept;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_hash)
|
||||
KV_SERIALIZE(tx_unsigned_hex)
|
||||
KV_SERIALIZE(outs_total)
|
||||
KV_SERIALIZE(amount_total)
|
||||
KV_SERIALIZE(outs_swept)
|
||||
KV_SERIALIZE(amount_swept)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
struct COMMAND_SIGN_TRANSFER
|
||||
{
|
||||
struct request
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace tools
|
|||
wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w), m_do_mint(false), m_deaf(false)
|
||||
{}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::run(bool do_mint, bool offline_mode)
|
||||
bool wallet_rpc_server::run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address)
|
||||
{
|
||||
static const uint64_t wallet_rpt_idle_work_period_ms = 2000;
|
||||
|
||||
|
|
@ -59,26 +59,41 @@ namespace tools
|
|||
|
||||
if (!offline_mode)
|
||||
{
|
||||
m_net_server.add_idle_handler([this]() -> bool
|
||||
m_net_server.add_idle_handler([this, &miner_address]() -> bool
|
||||
{
|
||||
size_t blocks_fetched = 0;
|
||||
bool received_money = false, ok = false;
|
||||
std::atomic<bool> stop(false);
|
||||
LOG_PRINT_L2("wallet RPC idle: refreshing...");
|
||||
m_wallet.refresh(blocks_fetched, received_money, ok, stop);
|
||||
if (stop)
|
||||
try
|
||||
{
|
||||
LOG_PRINT_L1("wallet RPC idle: refresh failed");
|
||||
return true;
|
||||
}
|
||||
size_t blocks_fetched = 0;
|
||||
bool received_money = false, ok = false;
|
||||
std::atomic<bool> stop(false);
|
||||
LOG_PRINT_L2("wallet RPC idle: refreshing...");
|
||||
m_wallet.refresh(blocks_fetched, received_money, ok, stop);
|
||||
if (stop)
|
||||
{
|
||||
LOG_PRINT_L1("wallet RPC idle: refresh failed");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_do_mint)
|
||||
if (m_do_mint)
|
||||
{
|
||||
bool has_related_alias_in_unconfirmed = false;
|
||||
LOG_PRINT_L2("wallet RPC idle: scanning tx pool...");
|
||||
m_wallet.scan_tx_pool(has_related_alias_in_unconfirmed);
|
||||
LOG_PRINT_L2("wallet RPC idle: trying to do PoS iteration...");
|
||||
m_wallet.try_mint_pos(miner_address);
|
||||
}
|
||||
}
|
||||
catch (error::no_connection_to_daemon&)
|
||||
{
|
||||
bool has_related_alias_in_unconfirmed = false;
|
||||
LOG_PRINT_L2("wallet RPC idle: scanning tx pool...");
|
||||
m_wallet.scan_tx_pool(has_related_alias_in_unconfirmed);
|
||||
LOG_PRINT_L2("wallet RPC idle: tring to do PoS iteration...");
|
||||
m_wallet.try_mint_pos();
|
||||
LOG_PRINT_RED("no connection to the daemon", LOG_LEVEL_0);
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
LOG_ERROR("exeption caught in wallet_rpc_server::idle_handler: " << e.what());
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LOG_ERROR("unknown exeption caught in wallet_rpc_server::idle_handler");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -387,6 +402,93 @@ namespace tools
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::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)
|
||||
{
|
||||
currency::payment_id_t payment_id;
|
||||
if (!req.payment_id_hex.empty() && !currency::parse_payment_id_from_hex_str(req.payment_id_hex, payment_id))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
|
||||
er.message = std::string("Invalid payment id: ") + req.payment_id_hex;
|
||||
return false;
|
||||
}
|
||||
|
||||
currency::account_public_address addr;
|
||||
currency::payment_id_t integrated_payment_id;
|
||||
if (!m_wallet.get_transfer_address(req.address, addr, integrated_payment_id))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
|
||||
er.message = std::string("Invalid address: ") + req.address;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!integrated_payment_id.empty())
|
||||
{
|
||||
if (!payment_id.empty())
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
|
||||
er.message = std::string("address ") + req.address + " has integrated payment id " + epee::string_tools::buff_to_hex_nodelimer(integrated_payment_id) +
|
||||
" which is incompatible with payment id " + epee::string_tools::buff_to_hex_nodelimer(payment_id) + " that was already assigned to this transfer";
|
||||
return false;
|
||||
}
|
||||
payment_id = integrated_payment_id;
|
||||
}
|
||||
|
||||
if (req.fee < m_wallet.get_core_runtime_config().tx_pool_min_fee)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_WRONG_ARGUMENT;
|
||||
er.message = std::string("Given fee is too low: ") + epee::string_tools::num_to_string_fast(req.fee) + ", minimum is: " + epee::string_tools::num_to_string_fast(m_wallet.get_core_runtime_config().tx_pool_min_fee);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
currency::transaction tx = AUTO_VAL_INIT(tx);
|
||||
size_t outs_total = 0, outs_swept = 0;
|
||||
uint64_t amount_total = 0, amount_swept = 0;
|
||||
|
||||
std::string unsigned_tx_blob_str;
|
||||
m_wallet.sweep_below(req.mixin, addr, req.amount, payment_id, req.fee, outs_total, amount_total, outs_swept, &tx, &unsigned_tx_blob_str);
|
||||
|
||||
get_inputs_money_amount(tx, amount_swept);
|
||||
res.amount_swept = amount_swept;
|
||||
res.amount_total = amount_total;
|
||||
res.outs_swept = outs_swept;
|
||||
res.outs_total = outs_total;
|
||||
|
||||
if (m_wallet.is_watch_only())
|
||||
{
|
||||
res.tx_unsigned_hex = epee::string_tools::buff_to_hex_nodelimer(unsigned_tx_blob_str); // watch-only wallets can't sign and relay transactions
|
||||
// leave res.tx_hash empty, because tx has will change after signing
|
||||
}
|
||||
else
|
||||
{
|
||||
res.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(tx));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (const tools::error::daemon_busy& e)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
|
||||
er.message = e.what();
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
|
||||
er.message = e.what();
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = "WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace tools
|
|||
|
||||
static void init_options(boost::program_options::options_description& desc);
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
bool run(bool do_mint, bool offline_mode);
|
||||
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);
|
||||
|
|
@ -47,6 +47,7 @@ namespace tools
|
|||
MAP_JON_RPC_WE("get_bulk_payments", on_get_bulk_payments, wallet_public::COMMAND_RPC_GET_BULK_PAYMENTS)
|
||||
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("sign_transfer", on_sign_transfer, wallet_public::COMMAND_SIGN_TRANSFER)
|
||||
MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_public::COMMAND_SUBMIT_TRANSFER)
|
||||
//contracts API
|
||||
|
|
@ -73,6 +74,7 @@ namespace tools
|
|||
bool on_get_bulk_payments(const wallet_public::COMMAND_RPC_GET_BULK_PAYMENTS::request& req, wallet_public::COMMAND_RPC_GET_BULK_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
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_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);
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ bool clean_data_directory()
|
|||
|
||||
for(auto& entry : boost::make_iterator_range(boost::filesystem::directory_iterator(config_folder), {}))
|
||||
{
|
||||
const std::string& fn_str = entry.path().filename().string();
|
||||
std::string fn_str = entry.path().filename().string();
|
||||
if (files.count(fn_str) != 0)
|
||||
{
|
||||
entries_to_remove.push_back(entry.path());
|
||||
|
|
@ -222,7 +222,7 @@ bool gen_and_play_intermitted_by_blockchain_saveload(const char* const genclass_
|
|||
auto after_init_cb = [crc, &alt_chains, &cps, core_time](currency::core& c)
|
||||
{
|
||||
c.get_blockchain_storage().set_core_runtime_config(crc); // restore runtime config
|
||||
c.get_blockchain_storage().set_alternative_chains(alt_chains); // restore alt chains
|
||||
c.get_blockchain_storage().set_alternative_chains(alt_chains); // restore alt chains
|
||||
c.get_blockchain_storage().get_checkpoints() = cps; // restore checkpoints
|
||||
test_core_time::adjust(core_time); // restore core time
|
||||
};
|
||||
|
|
@ -231,7 +231,7 @@ bool gen_and_play_intermitted_by_blockchain_saveload(const char* const genclass_
|
|||
{
|
||||
core_time = test_core_time::get_time(); // save core time
|
||||
crc = c.get_blockchain_storage().get_core_runtime_config(); // save runtime config
|
||||
c.get_blockchain_storage().get_alternative_chains(alt_chains); // save altchains
|
||||
c.get_blockchain_storage().get_alternative_chains(alt_chains); // save altchains
|
||||
cps = c.get_blockchain_storage().get_checkpoints(); // save checkpoints
|
||||
if (last_iter)
|
||||
core_state_after.fill(c);
|
||||
|
|
@ -250,7 +250,7 @@ bool gen_and_play_intermitted_by_blockchain_saveload(const char* const genclass_
|
|||
|
||||
|
||||
#define GENERATE_AND_PLAY(genclass) \
|
||||
if(!postponed_tests.count(#genclass) && (run_single_test.empty() || run_single_test == #genclass)) \
|
||||
if(!postponed_tests.count(#genclass) && (run_single_test.empty() || std::string::npos != std::string(#genclass).find(run_single_test))) \
|
||||
{ \
|
||||
TIME_MEASURE_START_MS(t); \
|
||||
++tests_count; \
|
||||
|
|
@ -359,6 +359,7 @@ private:
|
|||
size_t m_ev_index;
|
||||
test_core_listener* m_core_listener;
|
||||
|
||||
mutable std::unordered_map<crypto::hash, currency::transaction> m_onboard_txs;
|
||||
bool m_txs_kept_by_block;
|
||||
bool m_skip_txs_blobsize_check;
|
||||
|
||||
|
|
@ -389,11 +390,19 @@ public:
|
|||
|
||||
size_t pool_size = m_c.get_pool_transactions_count();
|
||||
currency::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
|
||||
m_c.handle_incoming_tx(tx_blob, tvc, m_txs_kept_by_block);
|
||||
bool tx_added = pool_size + 1 == m_c.get_pool_transactions_count();
|
||||
bool r = check_tx_verification_context(tvc, tx_added, m_ev_index, tx, m_validator);
|
||||
LOCAL_ASSERT(r);
|
||||
CHECK_AND_NO_ASSERT_MES(r, false, "tx verification context check failed");
|
||||
if (m_txs_kept_by_block)
|
||||
{
|
||||
m_onboard_txs[get_transaction_hash(tx)] = tx;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_c.handle_incoming_tx(tx_blob, tvc, m_txs_kept_by_block);
|
||||
bool tx_added = pool_size + 1 == m_c.get_pool_transactions_count();
|
||||
bool r = check_tx_verification_context(tvc, tx_added, m_ev_index, tx, m_validator);
|
||||
LOCAL_ASSERT(r);
|
||||
CHECK_AND_NO_ASSERT_MES(r, false, "tx verification context check failed");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -403,6 +412,7 @@ public:
|
|||
m_core_listener->before_block_pushed_to_core(b, blob_blk, m_c);
|
||||
|
||||
currency::block_verification_context bvc = AUTO_VAL_INIT(bvc);
|
||||
bvc.m_onboard_transactions.swap(m_onboard_txs);
|
||||
m_c.handle_incoming_block(blob_blk, bvc);
|
||||
bool r = check_block_verification_context(bvc, m_ev_index, b, m_validator);
|
||||
CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed");
|
||||
|
|
@ -655,7 +665,7 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_options, arg_run_single_test);
|
||||
command_line::add_arg(desc_options, arg_enable_debug_asserts);
|
||||
command_line::add_arg(desc_options, command_line::arg_data_dir, std::string("."));
|
||||
command_line::add_arg(desc_options, command_line::arg_db_engine);
|
||||
currency::core::init_options(desc_options);
|
||||
|
||||
bool r = command_line::handle_error_helper(desc_options, [&]()
|
||||
{
|
||||
|
|
@ -729,6 +739,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
#undef MARK_TEST_AS_POSTPONED
|
||||
|
||||
GENERATE_AND_PLAY(pos_minting_tx_packing);
|
||||
|
||||
GENERATE_AND_PLAY(multisig_wallet_test);
|
||||
GENERATE_AND_PLAY(multisig_wallet_test_many_dst);
|
||||
|
|
@ -764,7 +775,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(escrow_cancellation_acceptance_expiration);
|
||||
// GENERATE_AND_PLAY(escrow_proposal_acceptance_in_alt_chain); -- work in progress
|
||||
GENERATE_AND_PLAY(escrow_zero_amounts);
|
||||
GENERATE_AND_PLAY(escrow_acceptance_and_balance);
|
||||
GENERATE_AND_PLAY(escrow_balance);
|
||||
|
||||
GENERATE_AND_PLAY(escrow_altchain_meta_test<0>);
|
||||
GENERATE_AND_PLAY(escrow_altchain_meta_test<1>);
|
||||
|
|
@ -846,6 +857,7 @@ int main(int argc, char* argv[])
|
|||
GENERATE_AND_PLAY(wallet_outputs_with_same_key_image);
|
||||
GENERATE_AND_PLAY(wallet_unconfirmed_tx_expiration);
|
||||
GENERATE_AND_PLAY(wallet_unconfimed_tx_balance);
|
||||
GENERATE_AND_PLAY(packing_outputs_on_pos_minting_wallet);
|
||||
|
||||
GENERATE_AND_PLAY(wallet_rpc_integrated_address);
|
||||
GENERATE_AND_PLAY(wallet_rpc_integrated_address_transfer);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ struct gen_double_spend_in_the_same_block : public gen_double_spend_base< gen_do
|
|||
{
|
||||
static const uint64_t send_amount = MK_TEST_COINS(17);
|
||||
static const bool has_invalid_tx = !txs_kept_by_block;
|
||||
static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2;
|
||||
static const size_t expected_pool_txs_count = 1;
|
||||
static const uint64_t expected_bob_balance = send_amount;
|
||||
static const uint64_t expected_alice_balance = 0;
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ struct gen_double_spend_in_different_blocks : public gen_double_spend_base< gen_
|
|||
{
|
||||
static const uint64_t send_amount = MK_TEST_COINS(17);
|
||||
static const bool has_invalid_tx = !txs_kept_by_block;
|
||||
static const size_t expected_pool_txs_count = has_invalid_tx ? 0 : 1;
|
||||
static const size_t expected_pool_txs_count = 0;
|
||||
static const uint64_t expected_bob_balance = 0;
|
||||
static const uint64_t expected_alice_balance = send_amount - TESTS_DEFAULT_FEE;
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ struct gen_double_spend_in_alt_chain_in_the_same_block : public gen_double_spend
|
|||
{
|
||||
static const uint64_t send_amount = MK_TEST_COINS(17);
|
||||
static const bool has_invalid_tx = !txs_kept_by_block;
|
||||
static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2;
|
||||
static const size_t expected_pool_txs_count = txs_kept_by_block ? 0 :1;
|
||||
static const uint64_t expected_bob_balance = send_amount;
|
||||
static const uint64_t expected_alice_balance = 0;
|
||||
|
||||
|
|
@ -81,14 +81,12 @@ struct gen_double_spend_in_alt_chain_in_different_blocks : public gen_double_spe
|
|||
{
|
||||
static const uint64_t send_amount = MK_TEST_COINS(17);
|
||||
static const bool has_invalid_tx = !txs_kept_by_block;
|
||||
static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2;
|
||||
static const size_t expected_pool_txs_count = txs_kept_by_block ? 0:1;
|
||||
static const uint64_t expected_bob_balance = send_amount;
|
||||
static const uint64_t expected_alice_balance = 0;
|
||||
|
||||
static const uint64_t expected_alice_balance = 0;
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
};
|
||||
|
||||
|
||||
class gen_double_spend_in_different_chains : public test_chain_unit_base
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -3095,23 +3095,23 @@ bool escrow_zero_amounts::c1(currency::core& c, size_t ev_index, const std::vect
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
escrow_acceptance_and_balance::escrow_acceptance_and_balance()
|
||||
escrow_balance::escrow_balance()
|
||||
: m_alice_bob_start_amount(0)
|
||||
, m_alice_bob_start_chunk_amount(0)
|
||||
, m_alice_fee_proposal(0)
|
||||
, m_bob_fee_accept(0)
|
||||
, m_bob_fee_release(0)
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_not_confirmed);
|
||||
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_proposal_confirmed);
|
||||
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_not_confirmed);
|
||||
REGISTER_CALLBACK_METHOD(escrow_acceptance_and_balance, check_balance_after_acceptance_confirmed);
|
||||
REGISTER_CALLBACK_METHOD(escrow_balance, c1);
|
||||
}
|
||||
|
||||
bool escrow_acceptance_and_balance::generate(std::vector<test_event_entry>& events) const
|
||||
bool escrow_balance::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
// Test idea: carefull check balances on each stage of escrow contract (including cancellation req and acc):
|
||||
// 1) within wallet callback in the middle of contract function call
|
||||
// 2) after tx was sent to network but not yet confirmed
|
||||
// 3) after tx was confirmed
|
||||
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
|
||||
|
|
@ -3138,157 +3138,447 @@ bool escrow_acceptance_and_balance::generate(std::vector<test_event_entry>& even
|
|||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
|
||||
|
||||
// prepare contract details
|
||||
m_cpd = AUTO_VAL_INIT(m_cpd);
|
||||
m_cpd.amount_a_pledge = MK_TEST_COINS(7);
|
||||
m_cpd.amount_b_pledge = MK_TEST_COINS(5);
|
||||
m_cpd.amount_to_pay = MK_TEST_COINS(3);
|
||||
m_cpd.a_addr = alice_acc.get_public_address();
|
||||
m_cpd.b_addr = bob_acc.get_public_address();
|
||||
m_alice_fee_proposal = MK_TEST_COINS(4);
|
||||
m_bob_fee_accept = MK_TEST_COINS(2);
|
||||
m_bob_fee_release = MK_TEST_COINS(9); // Alice states that Bob should pay this much money for upcoming contract release (which will be sent by Alice)
|
||||
DO_CALLBACK(events, "c1");
|
||||
|
||||
std::vector<tx_source_entry> used_sources;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool escrow_balance::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
bool r = false, stub_bool = false;
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]);
|
||||
auto alice_bc = std::make_shared<wallet_callback_balance_checker>("Alice");
|
||||
alice_wlt->callback(alice_bc);
|
||||
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, m_accounts[BOB_ACC_IDX]);
|
||||
auto bob_bc = std::make_shared<wallet_callback_balance_checker>("Bob");
|
||||
bob_wlt->callback(bob_bc);
|
||||
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount, 0);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awainted out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount, 0);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
//
|
||||
// escrow proposal
|
||||
bc_services::proposal_body prop = AUTO_VAL_INIT(prop);
|
||||
transaction escrow_proposal_tx = AUTO_VAL_INIT(escrow_proposal_tx);
|
||||
r = build_custom_escrow_proposal(events, blk_1r, alice_acc.get_keys(), m_cpd, 0, 0, 0, blk_1r.timestamp + 36000, 0, m_alice_fee_proposal, m_bob_fee_release, eccf_normal, escrow_proposal_tx, used_sources, &prop);
|
||||
CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_proposal failed");
|
||||
events.push_back(escrow_proposal_tx);
|
||||
//
|
||||
bc_services::contract_private_details cpd = AUTO_VAL_INIT(cpd);
|
||||
cpd.amount_a_pledge = MK_TEST_COINS(7);
|
||||
cpd.amount_b_pledge = MK_TEST_COINS(5);
|
||||
cpd.amount_to_pay = MK_TEST_COINS(3);
|
||||
cpd.a_addr = m_accounts[ALICE_ACC_IDX].get_public_address();
|
||||
cpd.b_addr = m_accounts[BOB_ACC_IDX].get_public_address();
|
||||
uint64_t alice_proposal_fee = MK_TEST_COINS(4);
|
||||
uint64_t bob_acceptace_fee = MK_TEST_COINS(2);
|
||||
uint64_t bob_release_fee = MK_TEST_COINS(9); // Alice states that Bob should pay this much money for upcoming contract release (which will be sent by Alice)
|
||||
uint64_t alice_cancellation_request_fee = MK_TEST_COINS(1);
|
||||
|
||||
DO_CALLBACK(events, "check_balance_after_proposal_not_confirmed");
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount); // balace after sending the proposal
|
||||
|
||||
transaction proposal_tx = AUTO_VAL_INIT(proposal_tx);
|
||||
transaction escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx);
|
||||
uint64_t expiration_time = test_core_time::get_time() + 60;
|
||||
LOG_PRINT_GREEN("\n" "alice_wlt->send_escrow_proposal()", LOG_LEVEL_0);
|
||||
alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_time, alice_proposal_fee, bob_release_fee, "", proposal_tx, escrow_template_tx);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, escrow_proposal_tx);
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
DO_CALLBACK(events, "check_balance_after_proposal_confirmed");
|
||||
tools::wallet2::escrow_contracts_container contracts;
|
||||
r = alice_wlt->get_contracts(contracts);
|
||||
CHECK_AND_ASSERT_MES(r && contracts.size() == 1, false, "get_contracts() for Alice failed");
|
||||
crypto::hash contract_id = contracts.begin()->first;
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
|
||||
|
||||
DO_CALLBACK(events, "check_balance_after_proposal_confirmed");
|
||||
|
||||
// escrow proposal acceptance
|
||||
transaction escrow_normal_acceptance_tx = prop.tx_template;
|
||||
uint64_t normal_acceptance_mask = eccf_normal;
|
||||
r = build_custom_escrow_accept_proposal(events, blk_2, 0, bob_acc.get_keys(), m_cpd, 0, 0, 0, 0, m_bob_fee_accept, m_bob_fee_release, normal_acceptance_mask, prop.tx_onetime_secret_key, escrow_normal_acceptance_tx, used_sources);
|
||||
CHECK_AND_ASSERT_MES(r, false, "build_custom_escrow_accept_proposal failed");
|
||||
|
||||
events.push_back(escrow_normal_acceptance_tx);
|
||||
|
||||
DO_CALLBACK(events, "check_balance_after_acceptance_not_confirmed");
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, escrow_normal_acceptance_tx);
|
||||
|
||||
DO_CALLBACK(events, "check_balance_after_acceptance_confirmed");
|
||||
|
||||
MAKE_NEXT_BLOCK(events, blk_5, blk_4, miner_acc);
|
||||
|
||||
DO_CALLBACK(events, "check_balance_after_acceptance_confirmed");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool escrow_acceptance_and_balance::check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// proposal tx is not confirmed yet
|
||||
alice_bc->expect_balance();
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - m_alice_fee_proposal, // total
|
||||
m_alice_bob_start_amount - alice_proposal_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
MK_TEST_COINS(0) // awainted out
|
||||
0, // awaited in
|
||||
0 // awainted out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(!alice_bc->called(), false, "balance callback check failed");
|
||||
|
||||
// Bob's balance should not change
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount, m_alice_bob_start_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
MK_TEST_COINS(0) // awaited out
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool escrow_acceptance_and_balance::check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
|
||||
// mine a block to confirm escrow proposal tx
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// proposal tx is confirmed (balances should stay the same)
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - m_alice_fee_proposal, // total
|
||||
m_alice_bob_start_amount - alice_proposal_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
MK_TEST_COINS(0) // awaited out
|
||||
0, // awaited in
|
||||
0 // awainted out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount, m_alice_bob_start_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
MK_TEST_COINS(0) // awaited out
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
return true;
|
||||
}
|
||||
//
|
||||
// proposal acceptance
|
||||
//
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - m_alice_bob_start_chunk_amount);
|
||||
|
||||
bool escrow_acceptance_and_balance::check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
|
||||
LOG_PRINT_GREEN("\n" "bob_wlt->accept_proposal()", LOG_LEVEL_0);
|
||||
bob_wlt->accept_proposal(contract_id, bob_acceptace_fee);
|
||||
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// acceptance tx is not confirmed yet
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total
|
||||
m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
m_cpd.amount_a_pledge + m_cpd.amount_to_pay), // awaited out
|
||||
false, "");
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
cpd.amount_a_pledge + cpd.amount_to_pay // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance();
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total
|
||||
m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
m_cpd.amount_b_pledge + m_bob_fee_release), // awaited out
|
||||
false, "");
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
cpd.amount_b_pledge + bob_release_fee // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(!bob_bc->called(), false, "balance callback check failed");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool escrow_acceptance_and_balance::check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> alice_wlt = init_playtime_test_wallet(events, c, ALICE_ACC_IDX);
|
||||
std::shared_ptr<tools::wallet2> bob_wlt = init_playtime_test_wallet(events, c, BOB_ACC_IDX);
|
||||
// mine a block containing contract acceptance
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// acceptance tx is confirmed
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - m_alice_fee_proposal - m_cpd.amount_a_pledge - m_cpd.amount_to_pay, // total
|
||||
m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
MK_TEST_COINS(0) // awaited out
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount - m_cpd.amount_b_pledge - m_bob_fee_release - m_bob_fee_accept, // total
|
||||
m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
MK_TEST_COINS(0), // awaited in
|
||||
MK_TEST_COINS(0) // awaited out
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
//
|
||||
// cancellation request
|
||||
//
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay - alice_cancellation_request_fee, m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount);
|
||||
|
||||
LOG_PRINT_GREEN("\n" "alice_wlt->request_cancel_contract()", LOG_LEVEL_0);
|
||||
alice_wlt->request_cancel_contract(contract_id, alice_cancellation_request_fee, 60 * 60);
|
||||
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// cancellation request is not confirmed yet
|
||||
alice_bc->expect_balance();
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay - alice_cancellation_request_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(!alice_bc->called(), false, "balance callback check failed");
|
||||
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
// mine a block containing cancellation request
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// cancellation request is confirmed
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay - alice_cancellation_request_fee, m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay - alice_cancellation_request_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
//
|
||||
// cancellation acceptance
|
||||
//
|
||||
bob_bc->expect_balance();
|
||||
|
||||
LOG_PRINT_GREEN("\n" "bob_wlt->accept_cancel_contract()", LOG_LEVEL_0);
|
||||
bob_wlt->accept_cancel_contract(contract_id);
|
||||
|
||||
CHECK_AND_ASSERT_MES(!bob_bc->called(), false, "balance callback check failed");
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// cancellation acceptance is not confirmed yet
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee - alice_cancellation_request_fee, m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - alice_proposal_fee - alice_cancellation_request_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
cpd.amount_a_pledge + cpd.amount_to_pay, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount - bob_release_fee - bob_acceptace_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
cpd.amount_b_pledge, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
// mine a block containing cancellation acceptance
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// cancellation acceptance is confirmed
|
||||
alice_bc->expect_balance(m_alice_bob_start_amount - alice_proposal_fee - alice_cancellation_request_fee, m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_bob_start_amount - alice_proposal_fee - alice_cancellation_request_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 3 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(m_alice_bob_start_amount - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
m_alice_bob_start_amount - bob_release_fee - bob_acceptace_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 1 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
|
||||
//
|
||||
// Stage 2 : check normal contract workflow
|
||||
// don't check balances on request and accept as it was checked above
|
||||
//
|
||||
|
||||
uint64_t alice_balance_before_stage_2 = m_alice_bob_start_amount - alice_proposal_fee - alice_cancellation_request_fee;
|
||||
uint64_t bob_balance_before_stage_2 = m_alice_bob_start_amount - bob_release_fee - bob_acceptace_fee;
|
||||
|
||||
alice_bc->expect_balance(alice_balance_before_stage_2 - alice_proposal_fee, m_alice_bob_start_amount - 5 * m_alice_bob_start_chunk_amount);
|
||||
|
||||
LOG_PRINT_GREEN("\n" "stage2: alice_wlt->send_escrow_proposal()", LOG_LEVEL_0);
|
||||
proposal_tx = AUTO_VAL_INIT(proposal_tx);
|
||||
escrow_template_tx = AUTO_VAL_INIT(escrow_template_tx);
|
||||
alice_wlt->send_escrow_proposal(cpd, 0, 0, expiration_time, alice_proposal_fee, bob_release_fee, "", proposal_tx, escrow_template_tx);
|
||||
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
contracts.clear();
|
||||
r = alice_wlt->get_contracts(contracts);
|
||||
CHECK_AND_ASSERT_MES(r && contracts.size() == 2, false, "get_contracts() for Alice failed");
|
||||
// get new contract id
|
||||
if (contract_id != contracts.begin()->first)
|
||||
contract_id = contracts.begin()->first;
|
||||
else
|
||||
contract_id = (++contracts.begin())->first;
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
bob_wlt->refresh();
|
||||
|
||||
bob_bc->expect_balance(bob_balance_before_stage_2 - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount);
|
||||
|
||||
LOG_PRINT_GREEN("\n" "stage2: bob_wlt->accept_proposal()", LOG_LEVEL_0);
|
||||
bob_wlt->accept_proposal(contract_id, bob_acceptace_fee);
|
||||
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
alice_bc->expect_balance(alice_balance_before_stage_2 - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay, m_alice_bob_start_amount - 5 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
alice_balance_before_stage_2 - alice_proposal_fee - cpd.amount_a_pledge - cpd.amount_to_pay, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 5 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed");
|
||||
|
||||
bob_bc->expect_balance(bob_balance_before_stage_2 - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
bob_balance_before_stage_2 - cpd.amount_b_pledge - bob_release_fee - bob_acceptace_fee, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
//
|
||||
// contract release
|
||||
//
|
||||
|
||||
alice_bc->expect_balance();
|
||||
|
||||
alice_wlt->finish_contract(contract_id, BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL);
|
||||
|
||||
CHECK_AND_ASSERT_MES(!alice_bc->called(), false, "balance callback check failed");
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// contract release tx is unconfirmed
|
||||
alice_bc->expect_balance(alice_balance_before_stage_2 - alice_proposal_fee - cpd.amount_to_pay, m_alice_bob_start_amount - 5 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
alice_balance_before_stage_2 - alice_proposal_fee - cpd.amount_to_pay, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 5 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
cpd.amount_a_pledge, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(bob_balance_before_stage_2 - bob_release_fee - bob_acceptace_fee + cpd.amount_to_pay, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
bob_balance_before_stage_2 - bob_release_fee - bob_acceptace_fee + cpd.amount_to_pay, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
cpd.amount_b_pledge + cpd.amount_to_pay, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
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");
|
||||
CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
|
||||
|
||||
// contract release tx is confirmed
|
||||
alice_bc->expect_balance(alice_balance_before_stage_2 - alice_proposal_fee - cpd.amount_to_pay, m_alice_bob_start_amount - 5 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
alice_balance_before_stage_2 - alice_proposal_fee - cpd.amount_to_pay, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 5 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(alice_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
bob_bc->expect_balance(bob_balance_before_stage_2 - bob_release_fee - bob_acceptace_fee + cpd.amount_to_pay, m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Bob", bob_wlt,
|
||||
bob_balance_before_stage_2 - bob_release_fee - bob_acceptace_fee + cpd.amount_to_pay, // total
|
||||
true, UINT64_MAX,
|
||||
m_alice_bob_start_amount - 2 * m_alice_bob_start_chunk_amount, // unlocked
|
||||
0, // mined
|
||||
0, // awaited in
|
||||
0 // awaited out
|
||||
), false, "");
|
||||
CHECK_AND_ASSERT_MES(bob_bc->check(), false, "balance callback check failed, see above");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,19 +142,12 @@ struct escrow_zero_amounts : public wallet_test
|
|||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
||||
struct escrow_acceptance_and_balance : public wallet_test
|
||||
struct escrow_balance : public wallet_test
|
||||
{
|
||||
escrow_acceptance_and_balance();
|
||||
escrow_balance();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool check_balance_after_proposal_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_balance_after_proposal_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_balance_after_acceptance_not_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool check_balance_after_acceptance_confirmed(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
mutable uint64_t m_alice_bob_start_amount;
|
||||
mutable uint64_t m_alice_bob_start_chunk_amount;
|
||||
mutable uint64_t m_alice_fee_proposal;
|
||||
mutable uint64_t m_bob_fee_release;
|
||||
mutable uint64_t m_bob_fee_accept;
|
||||
mutable bc_services::contract_private_details m_cpd;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2361,7 +2361,7 @@ bool multisig_out_make_and_spent_in_altchain::generate(std::vector<test_event_en
|
|||
MAKE_NEXT_BLOCK(events, blk_5b, blk_4b, miner_acc);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_top_block", params_top_block(get_block_height(blk_5b), get_block_hash(blk_5b)));
|
||||
size_t tx_count = 1;
|
||||
size_t tx_count = 0;
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", tx_count);
|
||||
DO_CALLBACK(events, "clear_tx_pool");
|
||||
|
||||
|
|
|
|||
|
|
@ -1008,3 +1008,117 @@ bool pos_altblocks_validation::generate(std::vector<test_event_entry>& events) c
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
||||
pos_minting_tx_packing::pos_minting_tx_packing()
|
||||
: m_pos_mint_packing_size(5)
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(pos_minting_tx_packing, configure_core);
|
||||
REGISTER_CALLBACK_METHOD(pos_minting_tx_packing, c1);
|
||||
}
|
||||
|
||||
bool pos_minting_tx_packing::configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
pc.min_coinstake_age = 1;
|
||||
pc.pos_minimum_heigh = 1;
|
||||
c.get_blockchain_storage().set_core_runtime_config(pc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pos_minting_tx_packing::pos_minting_tx_packing::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
bool r = false;
|
||||
m_accounts.resize(TOTAL_ACCS_COUNT);
|
||||
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate();
|
||||
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate();
|
||||
|
||||
std::list<account_base> miner_acc_lst(1, miner_acc);
|
||||
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
|
||||
DO_CALLBACK(events, "configure_core");
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5);
|
||||
|
||||
m_alice_start_amount = 10 * CURRENCY_BLOCK_REWARD * m_pos_mint_packing_size;// +TESTS_DEFAULT_FEE;
|
||||
|
||||
transaction tx_1 = AUTO_VAL_INIT(tx_1);
|
||||
r = construct_tx_with_many_outputs(events, blk_0r, miner_acc.get_keys(), alice_acc.get_public_address(), m_alice_start_amount, 10, TESTS_DEFAULT_FEE, tx_1);
|
||||
CHECK_AND_ASSERT_MES(r, false, "construct_tx_with_many_outputs failed");
|
||||
|
||||
events.push_back(tx_1);
|
||||
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_1);
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pos_minting_tx_packing::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);
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, m_alice_start_amount, true, UINT64_MAX, m_alice_start_amount), false, "");
|
||||
|
||||
size_t pos_entries_count = 0;
|
||||
|
||||
for (size_t i = 0; i < m_pos_mint_packing_size; ++i)
|
||||
{
|
||||
r = mine_next_pos_block_in_playtime_with_wallet(*alice_wlt, m_accounts[ALICE_ACC_IDX].get_public_address(), pos_entries_count);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pos_block_in_playtime_with_wallet failed");
|
||||
alice_wlt->refresh();
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt, m_alice_start_amount + CURRENCY_BLOCK_REWARD * m_pos_mint_packing_size, true, UINT64_MAX), false, "");
|
||||
|
||||
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
|
||||
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_start_amount + CURRENCY_BLOCK_REWARD * m_pos_mint_packing_size, // total
|
||||
true,
|
||||
UINT64_MAX,
|
||||
m_alice_start_amount + CURRENCY_BLOCK_REWARD * m_pos_mint_packing_size // unlocked
|
||||
), false, "");
|
||||
|
||||
alice_wlt->set_pos_mint_packing_size(m_pos_mint_packing_size);
|
||||
|
||||
// no coinbase tx outputs should packed
|
||||
r = alice_wlt->try_mint_pos();
|
||||
CHECK_AND_ASSERT_MES(r, false, "try_mint_pos failed");
|
||||
|
||||
// make sure the wallet has only received new locked incoming reward
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_start_amount + CURRENCY_BLOCK_REWARD * (m_pos_mint_packing_size + 1), // total
|
||||
true,
|
||||
UINT64_MAX,
|
||||
m_alice_start_amount // unlocked (one output with amount == CURRENCY_BLOCK_REWARD * m_pos_mint_packing_size was spent as stake)
|
||||
), false, "");
|
||||
|
||||
r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE);
|
||||
CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed");
|
||||
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_start_amount + CURRENCY_BLOCK_REWARD * (m_pos_mint_packing_size + 1), // total
|
||||
true,
|
||||
UINT64_MAX,
|
||||
m_alice_start_amount + CURRENCY_BLOCK_REWARD * (m_pos_mint_packing_size + 1) // unlocked
|
||||
), false, "");
|
||||
|
||||
// coinbase tx outputs should be packed now, there's enough coinbase outputs (> m_pos_mint_packing_size)
|
||||
r = alice_wlt->try_mint_pos();
|
||||
CHECK_AND_ASSERT_MES(r, false, "try_mint_pos failed");
|
||||
|
||||
CHECK_AND_ASSERT_MES(refresh_wallet_and_check_balance("", "Alice", alice_wlt,
|
||||
m_alice_start_amount + CURRENCY_BLOCK_REWARD * (m_pos_mint_packing_size + 2), // total
|
||||
true,
|
||||
UINT64_MAX,
|
||||
m_alice_start_amount + CURRENCY_BLOCK_REWARD
|
||||
), false, "");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,3 +122,14 @@ struct pos_altblocks_validation : public wallet_test
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
||||
struct pos_minting_tx_packing : public wallet_test
|
||||
{
|
||||
pos_minting_tx_packing();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool configure_core(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
|
||||
mutable size_t m_pos_mint_packing_size;
|
||||
mutable size_t m_alice_start_amount;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1514,12 +1514,12 @@ bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events)
|
|||
events.push_back(tx_2);
|
||||
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(3));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
|
||||
// make a block with tx_0 and put tx_0 to the blockchain
|
||||
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, m_miner_acc, tx_0);
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
|
||||
// tx_1 and tx_2 is still in the pool
|
||||
// it can never be added to any block as long as blk_1 is in the blockchain due to key image conflict
|
||||
|
|
@ -1531,7 +1531,7 @@ bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events)
|
|||
MAKE_NEXT_BLOCK_TX1(events, blk_1a, blk_0r, m_miner_acc, tx_1);
|
||||
|
||||
// however, it does not remove tx from the pool
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
|
||||
//
|
||||
// make sure stuck tx will be removed from the pool when it's too old
|
||||
|
|
@ -1541,7 +1541,7 @@ bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events)
|
|||
|
||||
// remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool
|
||||
DO_CALLBACK(events, "remove_stuck_txs");
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
|
||||
// shift time by CURRENCY_MEMPOOL_TX_LIVETIME
|
||||
events.push_back(event_core_time(CURRENCY_MEMPOOL_TX_LIVETIME + 1, true));
|
||||
|
|
@ -1562,11 +1562,11 @@ bool tx_key_image_pool_conflict::generate(std::vector<test_event_entry>& events)
|
|||
events.push_back(tx_2);
|
||||
events.push_back(event_visitor_settings(event_visitor_settings::set_txs_kept_by_block, false));
|
||||
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
|
||||
// remove_stuck_txs should not remove anything, tx_1 and tx_2 should be in the pool
|
||||
DO_CALLBACK(events, "remove_stuck_txs");
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(2));
|
||||
DO_CALLBACK_PARAMS(events, "check_tx_pool_count", static_cast<size_t>(1));
|
||||
|
||||
// rewind 50 blocks so tx_0 spending its key image will be deep enough
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_3r, blk_3, m_miner_acc, 50);
|
||||
|
|
|
|||
|
|
@ -3297,3 +3297,79 @@ bool wallet_unconfimed_tx_balance::c1(currency::core& c, size_t ev_index, const
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
packing_outputs_on_pos_minting_wallet::packing_outputs_on_pos_minting_wallet()
|
||||
{
|
||||
REGISTER_CALLBACK_METHOD(packing_outputs_on_pos_minting_wallet, c1);
|
||||
REGISTER_CALLBACK_METHOD(packing_outputs_on_pos_minting_wallet, set_core_config);
|
||||
}
|
||||
bool packing_outputs_on_pos_minting_wallet::generate(std::vector<test_event_entry>& events) const
|
||||
{
|
||||
|
||||
// 0 10 11 21 22 <- blockchain height (assuming CURRENCY_MINED_MONEY_UNLOCK_WINDOW == 10)
|
||||
// (0 )... (0r)- (1 )... (1r)- <- main chain
|
||||
// tx_0 <- txs
|
||||
|
||||
GENERATE_ACCOUNT(miner_acc);
|
||||
m_accounts.push_back(miner_acc);
|
||||
//GENERATE_ACCOUNT(alice_acc);
|
||||
//m_accounts.push_back(alice_acc);
|
||||
|
||||
// don't use MAKE_GENESIS_BLOCK here because it will mask 'generator'
|
||||
currency::block blk_0 = AUTO_VAL_INIT(blk_0);
|
||||
generator.construct_genesis_block(blk_0, miner_acc, test_core_time::get_time());
|
||||
events.push_back(blk_0);
|
||||
|
||||
DO_CALLBACK(events, "set_core_config");
|
||||
|
||||
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW+5);
|
||||
|
||||
//MAKE_TX_FEE(events, tx_0, miner_acc, alice_acc, MK_TEST_COINS(2000), TESTS_DEFAULT_FEE, blk_0r);
|
||||
//MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
|
||||
//REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, WALLET_DEFAULT_TX_SPENDABLE_AGE);
|
||||
|
||||
DO_CALLBACK(events, "c1");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool packing_outputs_on_pos_minting_wallet::set_core_config(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
core_runtime_config crc = c.get_blockchain_storage().get_core_runtime_config();
|
||||
crc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH;
|
||||
crc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE;
|
||||
c.get_blockchain_storage().set_core_runtime_config(crc);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool packing_outputs_on_pos_minting_wallet::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
|
||||
{
|
||||
std::shared_ptr<tools::wallet2> miner_wlt = init_playtime_test_wallet(events, c, MINER_ACC_IDX);
|
||||
size_t blocks_fetched = 0;
|
||||
bool received_money;
|
||||
std::atomic<bool> atomic_false = ATOMIC_VAR_INIT(false);
|
||||
miner_wlt->refresh(blocks_fetched, received_money, atomic_false);
|
||||
CHECK_AND_ASSERT_MES(blocks_fetched == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5, false, "Incorrect numbers of blocks fetched");
|
||||
|
||||
miner_wlt->set_pos_mint_packing_size(4);
|
||||
check_balance_via_wallet(*miner_wlt.get(), "miner_wlt", MK_TEST_COINS(2000), 0, MK_TEST_COINS(2000), 0, 0);
|
||||
|
||||
miner_wlt->try_mint_pos();
|
||||
|
||||
CHECK_AND_ASSERT_MES(c.get_current_blockchain_size() == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 7, false, "Incorrect blockchain height:" << c.get_current_blockchain_size());
|
||||
miner_wlt->refresh(blocks_fetched, received_money, atomic_false);
|
||||
CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect numbers of blocks fetched");
|
||||
|
||||
block top_block = AUTO_VAL_INIT(top_block);
|
||||
bool r = c.get_blockchain_storage().get_top_block(top_block);
|
||||
CHECK_AND_ASSERT_MES(r && is_pos_block(top_block), false, "get_top_block failed or smth goes wrong");
|
||||
uint64_t top_block_reward = get_outs_money_amount(top_block.miner_tx);
|
||||
check_balance_via_wallet(*miner_wlt.get(), "miner_wlt", uint64_max, MK_TEST_COINS(2000) + top_block_reward, 0, 0, 0);
|
||||
|
||||
miner_wlt->reset_password(g_wallet_password);
|
||||
miner_wlt->store(g_wallet_filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -251,3 +251,11 @@ struct wallet_unconfimed_tx_balance : public wallet_test
|
|||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
||||
struct packing_outputs_on_pos_minting_wallet : public wallet_test
|
||||
{
|
||||
packing_outputs_on_pos_minting_wallet();
|
||||
bool generate(std::vector<test_event_entry>& events) const;
|
||||
bool set_core_config(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,3 +43,47 @@ protected:
|
|||
mutable test_generator generator;
|
||||
std::shared_ptr<tools::i_core_proxy> m_core_proxy;
|
||||
};
|
||||
|
||||
// wallet callback helper to check balance in wallet callbacks
|
||||
// see escrow_balance test for usage example
|
||||
struct wallet_callback_balance_checker : public tools::i_wallet2_callback
|
||||
{
|
||||
wallet_callback_balance_checker(const std::string& label) : m_label(label), m_result(true), m_called(false), m_balance(UINT64_MAX), m_unlocked_balance(UINT64_MAX), m_total_mined(UINT64_MAX) {}
|
||||
|
||||
void expect_balance(uint64_t balance = UINT64_MAX, uint64_t unlocked_balance = UINT64_MAX, uint64_t total_mined = UINT64_MAX)
|
||||
{
|
||||
m_balance = balance;
|
||||
m_unlocked_balance = unlocked_balance;
|
||||
m_total_mined = total_mined;
|
||||
m_called = false;
|
||||
}
|
||||
|
||||
virtual void on_transfer2(const tools::wallet_public::wallet_transfer_info& wti, uint64_t balance, uint64_t unlocked_balance, uint64_t total_mined) override
|
||||
{
|
||||
m_called = true;
|
||||
m_result = false;
|
||||
CHECK_AND_ASSERT_MES(m_balance == UINT64_MAX || balance == m_balance, (void)(0), m_label << " balance is incorrect: " << currency::print_money_brief(balance) << ", expected: " << currency::print_money_brief(m_balance));
|
||||
CHECK_AND_ASSERT_MES(m_unlocked_balance == UINT64_MAX || unlocked_balance == m_unlocked_balance, (void)(0), m_label << " unlocked balance is incorrect: " << currency::print_money_brief(unlocked_balance) << ", expected: " << currency::print_money_brief(m_unlocked_balance));
|
||||
CHECK_AND_ASSERT_MES(m_total_mined == UINT64_MAX || total_mined == m_total_mined, (void)(0), m_label << " total mined is incorrect: " << currency::print_money_brief(total_mined) << ", expected: " << currency::print_money_brief(m_total_mined));
|
||||
m_result = true;
|
||||
}
|
||||
|
||||
bool check()
|
||||
{
|
||||
bool result = m_result;
|
||||
m_result = false; // clear result to avoid errorneous successive calls to check() without calling except_balance()
|
||||
return result;
|
||||
}
|
||||
|
||||
bool called()
|
||||
{
|
||||
return m_called;
|
||||
}
|
||||
|
||||
bool m_result;
|
||||
bool m_called;
|
||||
std::string m_label;
|
||||
uint64_t m_balance;
|
||||
uint64_t m_unlocked_balance;
|
||||
uint64_t m_total_mined;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@
|
|||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
std::string exec(const char* cmd)
|
||||
std::string exec(const std::string& str)
|
||||
{
|
||||
std::array<char, 1024> buffer;
|
||||
|
||||
#if defined(WIN32)
|
||||
std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(cmd, "r"), _pclose);
|
||||
std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(str.c_str(), "r"), _pclose);
|
||||
#else
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
|
||||
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(str.c_str(), "r"), pclose);
|
||||
#endif
|
||||
|
||||
if (!pipe)
|
||||
|
|
@ -89,12 +89,13 @@ void free_space_check()
|
|||
bool r = false;
|
||||
|
||||
#ifdef WIN32
|
||||
output = exec("dir");
|
||||
std::string command = "dir";
|
||||
#else
|
||||
output = exec("df -h");
|
||||
std::string command = "df -h && df -i";
|
||||
#endif
|
||||
output = exec(command);
|
||||
|
||||
LOG_PRINT_L0("test command output:" << std::endl << output);
|
||||
LOG_PRINT_L0("test command " << command << ", output:" << std::endl << output);
|
||||
|
||||
r = try_write_test_file(test_file_size);
|
||||
LOG_PRINT_L0("test file write: " << (r ? "OK" : "fail"));
|
||||
|
|
@ -122,12 +123,9 @@ void free_space_check()
|
|||
}
|
||||
// free space is not ok!
|
||||
LOG_PRINT_YELLOW("1) fs::space() : available: " << si.available << ", free: " << si.free << ", capacity: " << si.capacity, LOG_LEVEL_0);
|
||||
#ifdef WIN32
|
||||
output = exec("dir");
|
||||
#else
|
||||
output = exec("df -h");
|
||||
#endif
|
||||
LOG_PRINT_YELLOW(output, LOG_LEVEL_0);
|
||||
|
||||
output = exec(command);
|
||||
LOG_PRINT_YELLOW("executed command: " << command << ", output: " << std::endl << output, LOG_LEVEL_0);
|
||||
|
||||
// try one again asap
|
||||
si = fs::space(current_path);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ int main(int argc, char** argv)
|
|||
epee::string_tools::set_module_name_and_folder(argv[0]);
|
||||
epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
|
||||
epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2);
|
||||
epee::log_space::log_singletone::add_logger(LOGGER_FILE,
|
||||
epee::log_space::log_singletone::get_default_log_file().c_str(),
|
||||
epee::log_space::log_singletone::get_default_log_folder().c_str());
|
||||
|
||||
//run_serialization_performance_test();
|
||||
//return 1;
|
||||
|
|
|
|||
|
|
@ -428,3 +428,23 @@ TEST(db_accessor_tests, median_db_cache_test)
|
|||
|
||||
m_naive_median.print_to_file(folder_name + "/naive_median_2.txt");
|
||||
}
|
||||
|
||||
|
||||
TEST(db_accessor_tests, dtor_without_init)
|
||||
{
|
||||
epee::shared_recursive_mutex m_rw_lock;
|
||||
|
||||
{
|
||||
tools::db::basic_db_accessor m_db(nullptr, m_rw_lock);
|
||||
ASSERT_FALSE(m_db.is_open());
|
||||
}
|
||||
|
||||
// make sure dtor called successfully with no exceptions
|
||||
|
||||
{
|
||||
tools::db::basic_db_accessor m_db(nullptr, m_rw_lock);
|
||||
m_db.close();
|
||||
ASSERT_FALSE(m_db.is_open());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
#include <memory>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <boost/format.hpp>
|
||||
#include <bitset>
|
||||
|
||||
#include "epee/include/include_base_utils.h"
|
||||
|
||||
|
|
@ -14,6 +16,7 @@
|
|||
#include "common/db_abstract_accessor.h"
|
||||
#include "common/db_backend_lmdb.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "common/db_backend_mdbx.h"
|
||||
|
||||
using namespace tools;
|
||||
|
||||
|
|
@ -890,7 +893,8 @@ namespace lmdb_test
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 2gb_test
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
TEST(lmdb, 2gb_test)
|
||||
template<typename db_backend_t>
|
||||
void db_2gb_test()
|
||||
{
|
||||
bool r = false;
|
||||
epee::shared_recursive_mutex rw_lock;
|
||||
|
|
@ -899,9 +903,9 @@ namespace lmdb_test
|
|||
|
||||
static const uint64_t buffer_size = 64 * 1024; // 64 KB
|
||||
static const uint64_t db_total_size = static_cast<uint64_t>(2.1 * 1024 * 1024 * 1024); // 2.1 GB -- a bit more than 2GB to test 2GB boundary
|
||||
static const std::string db_file_path = "2gb_lmdb_test";
|
||||
static const std::string db_file_path = std::string("2gb_") + typeid(db_backend_t).name() + "_test";
|
||||
|
||||
std::shared_ptr<db::lmdb_db_backend> lmdb_ptr = std::make_shared<db::lmdb_db_backend>();
|
||||
std::shared_ptr<db_backend_t> lmdb_ptr = std::make_shared<db_backend_t>();
|
||||
db::basic_db_accessor bdba(lmdb_ptr, rw_lock);
|
||||
|
||||
//
|
||||
|
|
@ -922,6 +926,27 @@ namespace lmdb_test
|
|||
buffer.resize(buffer_size);
|
||||
crypto::generate_random_bytes(buffer_size, buffer.data());
|
||||
|
||||
std::vector<std::vector<uint8_t>> buffer_paranoidal_copies;
|
||||
buffer_paranoidal_copies.resize(3);
|
||||
for (size_t i = 0; i < buffer_paranoidal_copies.size(); ++i)
|
||||
buffer_paranoidal_copies[i].assign(buffer.begin(), buffer.end());
|
||||
|
||||
auto check_buffer_paranoidal_copies = [&]() {
|
||||
for (size_t buffer_index = 0; buffer_index < buffer_paranoidal_copies.size(); ++buffer_index)
|
||||
{
|
||||
for(size_t i = 0; i < buffer_size; ++i)
|
||||
{
|
||||
if (buffer[i] != buffer_paranoidal_copies[buffer_index][i])
|
||||
{
|
||||
std::cout << "!!! buffer differs from paranoidal copy #" << buffer_index << " at byte " << i << ": " << static_cast<uint32_t>(buffer[i]) << " != " << static_cast<uint32_t>(buffer_paranoidal_copies[buffer_index][i]) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
check_buffer_paranoidal_copies();
|
||||
|
||||
uint64_t total_data = 0;
|
||||
for (uint64_t key = 0; key < db_total_size / buffer_size; ++key)
|
||||
{
|
||||
|
|
@ -963,7 +988,58 @@ namespace lmdb_test
|
|||
ASSERT_TRUE(r);
|
||||
ASSERT_EQ(buffer_size, out_buffer.size());
|
||||
|
||||
ASSERT_TRUE(0 == memcmp(buffer.data(), out_buffer.c_str(), buffer_size));
|
||||
if (memcmp(buffer.data(), out_buffer.c_str(), buffer_size) != 0)
|
||||
{
|
||||
// read data doesn't match with written one
|
||||
std::cout << "ERROR: data missmatch at key " << key << ", total_data = " << total_data << std::endl;
|
||||
|
||||
// paranoid checks
|
||||
check_buffer_paranoidal_copies();
|
||||
|
||||
size_t wrong_bytes = 0;
|
||||
size_t wrong_bytes_min_idx = SIZE_MAX;
|
||||
size_t wrong_bytes_max_idx = 0;
|
||||
for (size_t i = 0; i < buffer_size; ++i)
|
||||
{
|
||||
if (buffer[i] != static_cast<unsigned char>(out_buffer[i]))
|
||||
{
|
||||
++wrong_bytes;
|
||||
if (wrong_bytes_min_idx == SIZE_MAX)
|
||||
wrong_bytes_min_idx = i;
|
||||
if (wrong_bytes_max_idx < i)
|
||||
wrong_bytes_max_idx = i;
|
||||
if (wrong_bytes < 10)
|
||||
{
|
||||
std::cout << "wrong byte at buffer offset " << boost::format("0x%04x") % i << ", file offset " << boost::format("0x%08x") % (total_data + i) << ": " <<
|
||||
boost::format("%02x") % static_cast<unsigned int>(static_cast<unsigned char>(out_buffer[i])) << " = " << std::bitset<8>(out_buffer[i]) << " instead of " <<
|
||||
boost::format("%02x") % static_cast<unsigned int>(buffer[i]) << " = " << std::bitset<8>(buffer[i]) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "wrong bytes: " << wrong_bytes << " of " << buffer_size << " (" << std::fixed << std::setprecision(2) << 100.0 * wrong_bytes / buffer_size << "%)" << std::endl;
|
||||
|
||||
size_t line_len = 32;
|
||||
size_t wrong_bytes_min_line = wrong_bytes_min_idx / line_len;
|
||||
size_t wrong_bytes_max_line = wrong_bytes_max_idx / line_len + 1;
|
||||
|
||||
for (size_t l = wrong_bytes_min_line; l < wrong_bytes_max_line; ++l)
|
||||
{
|
||||
std::cout << boost::format("\n0x%04x ") % ( l * line_len );
|
||||
|
||||
for(size_t i = l * line_len; i < (l + 1) * line_len; ++i)
|
||||
std::cout << boost::format("%02x") % static_cast<unsigned int>(buffer[i]) << (i % 4 == 3 ? " " : "");
|
||||
|
||||
std::cout << " ";
|
||||
|
||||
for(size_t i = l * line_len; i < (l + 1) * line_len; ++i)
|
||||
std::cout << boost::format("%02x") % static_cast<unsigned int>(static_cast<unsigned char>(out_buffer[i])) << (i % 4 == 3 ? " " : "");
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
|
||||
ASSERT_TRUE(false);
|
||||
}
|
||||
|
||||
total_data += buffer_size;
|
||||
if (key % 1024 == 0)
|
||||
|
|
@ -979,4 +1055,14 @@ namespace lmdb_test
|
|||
|
||||
}
|
||||
|
||||
TEST(lmdb, 2gb_test)
|
||||
{
|
||||
db_2gb_test<db::lmdb_db_backend>();
|
||||
}
|
||||
|
||||
TEST(mdbx, 2gb_test)
|
||||
{
|
||||
db_2gb_test<db::mdbx_db_backend>();
|
||||
}
|
||||
|
||||
} // namespace lmdb_test
|
||||
|
|
|
|||
|
|
@ -38,9 +38,9 @@ if [ $? -ne 0 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
make -j connectivity_tool;
|
||||
make -j connectivity_tool daemon simplewallet
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to make!"
|
||||
echo "Failed to make binaries!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -66,11 +66,17 @@ if [ $? -ne 0 ]; then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
cp zanod simplewallet Zano.app/Contents/MacOS/
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Failed to copy binaries to Zano.app folder"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# fix boost libs paths in main executable and libs to workaround El Capitan's SIP restrictions
|
||||
source ../../../utils/macosx_fix_boost_libs_path.sh
|
||||
fix_boost_libs_in_binary @executable_path/../Frameworks/boost_libs Zano.app/Contents/MacOS/Zano
|
||||
fix_boost_libs_in_binary @executable_path/../Frameworks/boost_libs Zano.app/Contents/MacOS/simplewallet
|
||||
fix_boost_libs_in_binary @executable_path/../Frameworks/boost_libs Zano.app/Contents/MacOS/zanod
|
||||
fix_boost_libs_in_libs @executable_path/../Frameworks/boost_libs Zano.app/Contents/Frameworks/boost_libs
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue