forked from lthn/blockchain
Merge remote-tracking branch 'origin/frontend'
This commit is contained in:
commit
afc2e972d1
87 changed files with 3570 additions and 956 deletions
|
|
@ -45,6 +45,10 @@ if (UNIX AND NOT APPLE)
|
|||
find_package(Threads REQUIRED)
|
||||
endif()
|
||||
|
||||
# TODO(unassigned): expand on types and versions, and then refactor.
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CLANG TRUE)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions("/bigobj /Zm1000 /Z7 /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4503 /wd4345 /wd4091 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__")
|
||||
|
|
@ -66,7 +70,6 @@ else()
|
|||
# if(NOT APPLE)
|
||||
# set(WARNINGS "${WARNINGS} -Werror")
|
||||
# endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set(WARNINGS "${WARNINGS} -Wno-shift-count-overflow -Wno-error=mismatched-tags -Wno-error=null-conversion -Wno-overloaded-shift-op-parentheses -Wno-error=shift-count-overflow -Wno-error=tautological-constant-out-of-range-compare -Wno-error=unused-private-field -Wno-error=unneeded-internal-declaration")
|
||||
else()
|
||||
|
|
@ -103,13 +106,15 @@ else()
|
|||
else()
|
||||
set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert")
|
||||
endif()
|
||||
set(LINUX_LD_GOLD "")
|
||||
set(LINUX_STATIC_ICU "")
|
||||
if((NOT APPLE) AND (NOT MSVC))
|
||||
set(LINUX_LD_GOLD "-fuse-ld=gold")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -ftemplate-depth-1024 -std=c++11 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
|
||||
if (NOT APPLE AND NOT MSVC)
|
||||
if (CLANG)
|
||||
set(LLVM_USE_LINKER "gold")
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
|
||||
endif()
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LINUX_LD_GOLD} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LINUX_LD_GOLD} -fpermissive -ftemplate-depth-1024 -std=c++11 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8))
|
||||
set(DEBUG_FLAGS "-g3 -O0") #set(DEBUG_FLAGS "-g3 -Og")
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ Building
|
|||
### Dependencies
|
||||
| component / version | minimum <br>(not recommended but may work) | recommended | most recent of what we have ever tested |
|
||||
|--|--|--|--|
|
||||
| gcc (Linux) | 5.4.0 | 7.2.0 | 7.2.0 |
|
||||
| gcc (Linux) | 5.4.0 | 7.2.0 | 8.2.1 |
|
||||
| llvm/clang (Linux) | UNKNOWN | 7.0.1 | 7.0.1 |
|
||||
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2015 (14.0 update 1) | 2015 (14.0 update 3) | 2017 (15.5.7) |
|
||||
| [XCode](https://developer.apple.com/downloads/) (macOS) | 7.3.1 | 9.2 | 9.2 |
|
||||
| [CMake](https://cmake.org/download/) | 2.8.6 | 3.4.1 | 3.11.0 |
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ add_subdirectory(liblmdb)
|
|||
if(MSVC)
|
||||
target_compile_options(lmdb PRIVATE /wd4996 /wd4503 /wd4345 /wd4267 /wd4244 /wd4146 /wd4333 /wd4172)
|
||||
else()
|
||||
target_compile_options(lmdb PRIVATE -Wno-discarded-qualifiers -Wno-empty-body -Wno-unused-but-set-variable)
|
||||
# Warnings as used by LMDB itself (LMDB_0.9.23)
|
||||
target_compile_options(lmdb PRIVATE -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -35,12 +35,11 @@ namespace eos {
|
|||
|
||||
// version of the linked boost archive library
|
||||
const archive_version_type archive_version(
|
||||
11
|
||||
// #if BOOST_VERSION < 103700
|
||||
// boost::archive::ARCHIVE_VERSION()
|
||||
// #else
|
||||
// boost::archive::BOOST_ARCHIVE_VERSION()
|
||||
// #endif
|
||||
#if BOOST_VERSION < 103700
|
||||
boost::archive::ARCHIVE_VERSION()
|
||||
#else
|
||||
boost::archive::BOOST_ARCHIVE_VERSION()
|
||||
#endif
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* \file portable_iarchive.hpp
|
||||
* \brief Provides an archive to read from portable binary files.
|
||||
* \author christian.pfligersdorffer@gmx.at
|
||||
* \version 5.0
|
||||
* \version 5.1
|
||||
*
|
||||
* This pair of archives brings the advantages of binary streams to the cross
|
||||
* platform boost::serialization user. While being almost as fast as the native
|
||||
|
|
@ -23,6 +23,9 @@
|
|||
* chance it will instantly work for your specific setup. If you encounter
|
||||
* problems or have suggestions please contact the author.
|
||||
*
|
||||
* \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to
|
||||
* ecotax for pointing to the issue with shared_ptr_helper.
|
||||
*
|
||||
* \note Version 5.0 is now compatible with boost up to version 1.49 and enables
|
||||
* serialization of std::wstring by converting it to/from utf8 (thanks to
|
||||
* Arash Abghari for this suggestion). With that all unit tests from the
|
||||
|
|
@ -89,9 +92,7 @@
|
|||
#include <boost/archive/basic_binary_iprimitive.hpp>
|
||||
#include <boost/archive/basic_binary_iarchive.hpp>
|
||||
|
||||
#if BOOST_VERSION >= 105600
|
||||
#include <boost/serialization/shared_ptr_helper.hpp>
|
||||
#elif BOOST_VERSION >= 103500
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
#include <boost/archive/shared_ptr_helper.hpp>
|
||||
#endif
|
||||
|
||||
|
|
@ -115,14 +116,16 @@
|
|||
#include <boost/math/fpclassify.hpp>
|
||||
#elif BOOST_VERSION < 104800
|
||||
#include <boost/spirit/home/support/detail/integer/endian.hpp>
|
||||
// Boost 1.69 (Spirit.X2/X3) has dropped their own FP routines in favor of boost::math
|
||||
#elif BOOST_VERSION < 106900
|
||||
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#else
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
|
||||
#endif
|
||||
|
||||
// namespace alias
|
||||
#if BOOST_VERSION < 103800
|
||||
#if BOOST_VERSION < 103800 || BOOST_VERSION >= 106900
|
||||
namespace fp = boost::math;
|
||||
#else
|
||||
namespace fp = boost::spirit::math;
|
||||
|
|
@ -135,7 +138,7 @@ namespace endian = boost::detail;
|
|||
namespace endian = boost::spirit::detail;
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
|
||||
// used for wstring to utf8 conversion
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
|
|
@ -190,9 +193,7 @@ namespace eos {
|
|||
// load_override functions so we chose to stay one level higher
|
||||
, public boost::archive::basic_binary_iarchive<portable_iarchive>
|
||||
|
||||
#if BOOST_VERSION >= 105600
|
||||
// mix-in helper class for serializing shared_ptr does not exist anymore
|
||||
#elif BOOST_VERSION >= 103500
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
// mix-in helper class for serializing shared_ptr
|
||||
, public boost::archive::detail::shared_ptr_helper
|
||||
#endif
|
||||
|
|
@ -349,7 +350,7 @@ namespace eos {
|
|||
T temp = size < 0 ? -1 : 0;
|
||||
load_binary(&temp, abs(size));
|
||||
|
||||
// load the value from little endian - is is then converted
|
||||
// load the value from little endian - it is then converted
|
||||
// to the target type T and fits it because size <= sizeof(T)
|
||||
t = endian::load_little_endian<T, sizeof(T)>(&temp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* \file portable_oarchive.hpp
|
||||
* \brief Provides an archive to create portable binary files.
|
||||
* \author christian.pfligersdorffer@gmx.at
|
||||
* \version 5.0
|
||||
* \version 5.1
|
||||
*
|
||||
* This pair of archives brings the advantages of binary streams to the cross
|
||||
* platform boost::serialization user. While being almost as fast as the native
|
||||
|
|
@ -23,6 +23,9 @@
|
|||
* chance it will instantly work for your specific setup. If you encounter
|
||||
* problems or have suggestions please contact the author.
|
||||
*
|
||||
* \note Version 5.1 is now compatible with boost up to version 1.59. Thanks to
|
||||
* ecotax for pointing to the issue with shared_ptr_helper.
|
||||
*
|
||||
* \note Version 5.0 is now compatible with boost up to version 1.49 and enables
|
||||
* serialization of std::wstring by converting it to/from utf8 (thanks to
|
||||
* Arash Abghari for this suggestion). With that all unit tests from the
|
||||
|
|
@ -91,15 +94,9 @@
|
|||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/archive/basic_binary_oprimitive.hpp>
|
||||
#include <boost/archive/basic_binary_oarchive.hpp>
|
||||
#if BOOST_VERSION >= 105600
|
||||
#include <boost/serialization/shared_ptr_helper.hpp>
|
||||
#elif BOOST_VERSION >= 103500
|
||||
#include <boost/archive/shared_ptr_helper.hpp>
|
||||
#endif
|
||||
|
||||
#if BOOST_VERSION >= 104500
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
#include <boost/archive/shared_ptr_helper.hpp>
|
||||
#endif
|
||||
|
||||
// funny polymorphics
|
||||
|
|
@ -122,14 +119,16 @@
|
|||
#include <boost/math/fpclassify.hpp>
|
||||
#elif BOOST_VERSION < 104800
|
||||
#include <boost/spirit/home/support/detail/integer/endian.hpp>
|
||||
// Boost 1.69 (Spirit.X2/X3) has dropped their own FP routines in favor of boost::math
|
||||
#elif BOOST_VERSION < 106900
|
||||
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#else
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
|
||||
#endif
|
||||
|
||||
// namespace alias fp_classify
|
||||
#if BOOST_VERSION < 103800
|
||||
#if BOOST_VERSION < 103800 || BOOST_VERSION >= 106900
|
||||
namespace fp = boost::math;
|
||||
#else
|
||||
namespace fp = boost::spirit::math;
|
||||
|
|
@ -142,7 +141,7 @@ namespace endian = boost::detail;
|
|||
namespace endian = boost::spirit::detail;
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
#if BOOST_VERSION >= 104500 && !defined BOOST_NO_STD_WSTRING
|
||||
// used for wstring to utf8 conversion
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
|
|
@ -195,9 +194,7 @@ namespace eos {
|
|||
// save_override functions so we chose to stay one level higher
|
||||
, public boost::archive::basic_binary_oarchive<portable_oarchive>
|
||||
|
||||
#if BOOST_VERSION >= 105600
|
||||
// mix-in helper class for serializing shared_ptr does not exist anymore
|
||||
#elif BOOST_VERSION >= 103500
|
||||
#if BOOST_VERSION >= 103500 && BOOST_VERSION < 105600
|
||||
// mix-in helper class for serializing shared_ptr
|
||||
, public boost::archive::detail::shared_ptr_helper
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -893,12 +893,10 @@ namespace log_space
|
|||
FAST_CRITICAL_REGION_END();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string get_thread_prefix()
|
||||
{
|
||||
FAST_CRITICAL_REGION_LOCAL(m_critical_sec);
|
||||
return m_thr_prefix_strings[misc_utils::get_thread_string_id()];
|
||||
|
||||
}
|
||||
|
||||
std::string get_default_log_file()
|
||||
|
|
@ -1160,7 +1158,6 @@ namespace log_space
|
|||
|
||||
}
|
||||
|
||||
|
||||
static bool add_logger( ibase_log_stream* pstream, int log_level_limit = LOG_LEVEL_4 )
|
||||
{
|
||||
logger* plogger = get_or_create_instance();
|
||||
|
|
@ -1234,8 +1231,6 @@ POP_WARNINGS
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
|
||||
|
|
@ -1290,8 +1285,6 @@ POP_WARNINGS
|
|||
return plogger->get_thread_prefix();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static std::string get_prefix_entry()
|
||||
{
|
||||
std::stringstream str_prefix;
|
||||
|
|
@ -1587,8 +1580,6 @@ POP_WARNINGS
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define LOG_PRINT_NO_POSTFIX(mess, level) LOG_PRINT_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level)
|
||||
#define LOG_PRINT_NO_PREFIX(mess, level) LOG_PRINT_NO_PREFIX2(LOG_DEFAULT_TARGET, mess, level)
|
||||
#define LOG_PRINT_NO_PREFIX_NO_POSTFIX(mess, level) LOG_PRINT_NO_PREFIX_NO_POSTFIX2(LOG_DEFAULT_TARGET, mess, level)
|
||||
|
|
@ -1694,7 +1685,6 @@ POP_WARNINGS
|
|||
#define CHECK_AND_ASSERT_MES2(expr, message) do{if(!(expr)) {LOG_ERROR(message); };}while(0)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
POP_WARNINGS
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ namespace net_utils
|
|||
bool m_is_stop_handling;
|
||||
http::http_request_info m_query_info;
|
||||
size_t m_len_summary, m_len_remain;
|
||||
size_t m_precommand_line_chars;
|
||||
config_type& m_config;
|
||||
bool m_want_close;
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -33,8 +33,9 @@
|
|||
#include "file_io_utils.h"
|
||||
#include "net_parse_helpers.h"
|
||||
|
||||
#define HTTP_MAX_URI_LEN 9000
|
||||
#define HTTP_MAX_HEADER_LEN 100000
|
||||
#define HTTP_MAX_URI_LEN 9000
|
||||
#define HTTP_MAX_PRE_COMMAND_LINE_CHARS 20
|
||||
#define HTTP_MAX_HEADER_LEN 100000
|
||||
|
||||
PUSH_WARNINGS
|
||||
DISABLE_GCC_WARNING(maybe-uninitialized)
|
||||
|
|
@ -204,7 +205,8 @@ namespace net_utils
|
|||
m_len_remain(0),
|
||||
m_config(config),
|
||||
m_want_close(false),
|
||||
m_psnd_hndlr(psnd_hndlr)
|
||||
m_psnd_hndlr(psnd_hndlr),
|
||||
m_precommand_line_chars(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -217,6 +219,7 @@ namespace net_utils
|
|||
m_body_transfer_type = http_body_transfer_undefined;
|
||||
m_query_info.clear();
|
||||
m_len_summary = 0;
|
||||
m_precommand_line_chars = 0;
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
|
@ -257,11 +260,19 @@ namespace net_utils
|
|||
if((m_cache[0] == '\r' || m_cache[0] == '\n'))
|
||||
{
|
||||
//some times it could be that before query line cold be few line breaks
|
||||
//so we have to be calm without panic with assers
|
||||
//so we have to be calm down without panic and asserts
|
||||
m_cache.erase(0, 1);
|
||||
|
||||
//fixed bug with possible '\r\n' chars flood, thanks to @anonimal (https://github.com/anonimal) for pointing this
|
||||
++m_precommand_line_chars;
|
||||
if (m_precommand_line_chars > HTTP_MAX_PRE_COMMAND_LINE_CHARS)
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long URI line");
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(std::string::npos != m_cache.find('\n', 0))
|
||||
handle_invoke_query_line();
|
||||
else
|
||||
|
|
@ -269,7 +280,7 @@ namespace net_utils
|
|||
m_is_stop_handling = true;
|
||||
if(m_cache.size() > HTTP_MAX_URI_LEN)
|
||||
{
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_out: Too long URI line");
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Too long URI line");
|
||||
m_state = http_state_error;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -297,10 +308,10 @@ namespace net_utils
|
|||
case http_state_connection_close:
|
||||
return false;
|
||||
default:
|
||||
LOG_ERROR("simple_http_connection_handler::handle_char_out: Wrong state: " << m_state);
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Wrong state: " << m_state);
|
||||
return false;
|
||||
case http_state_error:
|
||||
LOG_ERROR("simple_http_connection_handler::handle_char_out: Error state!!!");
|
||||
LOG_ERROR("simple_http_connection_handler::handle_buff_in: Error state!!!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -334,10 +345,10 @@ namespace net_utils
|
|||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::handle_invoke_query_line()
|
||||
{
|
||||
LOG_FRAME("simple_http_connection_handler<t_connection_context>::handle_recognize_protocol_out(*)", LOG_LEVEL_3);
|
||||
LOG_FRAME("simple_http_connection_handler<t_connection_context>::handle_invoke_query_line(*)", LOG_LEVEL_3);
|
||||
|
||||
STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal);
|
||||
// 123 4 5 6 7 8 9 10 11 12
|
||||
// 123 4 5 6 7 8 9 10 11 12
|
||||
//size_t match_len = 0;
|
||||
boost::smatch result;
|
||||
if(boost::regex_search(m_cache, result, rexp_match_command_line, boost::match_default) && result[0].matched)
|
||||
|
|
@ -682,4 +693,4 @@ namespace net_utils
|
|||
POP_WARNINGS
|
||||
//--------------------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------------------
|
||||
//--------------------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -701,6 +701,11 @@ namespace epee
|
|||
#define CRITICAL_REGION_BEGIN1(x) CRITICAL_REGION_BEGIN_VAR(x, critical_region_var1)
|
||||
#define CRITICAL_REGION_END() }
|
||||
|
||||
#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)
|
||||
|
||||
#define SHARED_CRITICAL_REGION_BEGIN(x) { SHARED_CRITICAL_REGION_LOCAL(x)
|
||||
#define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { EXCLUSIVE_CRITICAL_REGION_LOCAL(x)
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ add_library(common ${COMMON})
|
|||
add_dependencies(common version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(COMMON)
|
||||
|
||||
if(NOT MSVC AND NOT APPLE)
|
||||
if(NOT MSVC AND NOT APPLE AND NOT CLANG) # TODO(unassigned): do we really need the clang equivalent?
|
||||
target_compile_options(common PRIVATE -fno-var-tracking-assignments)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
36
src/common/crypto_stream_operators.h
Normal file
36
src/common/crypto_stream_operators.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// 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 <string>
|
||||
#include <sstream>
|
||||
#include "include_base_utils.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
//------
|
||||
bool parse_hash256(const std::string str_hash, crypto::hash& hash);
|
||||
template <class T>
|
||||
std::ostream &print256(std::ostream &o, const T &v) {
|
||||
return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::ostream &print16(std::ostream &o, const T &v) {
|
||||
return o << "<" << epee::string_tools::pod_to_hex(v).substr(0, 5) << "..>";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string print16(const T &v) {
|
||||
return std::string("<") + epee::string_tools::pod_to_hex(v).substr(0, 5) + "..>";
|
||||
}
|
||||
|
||||
|
||||
namespace crypto {
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); }
|
||||
}
|
||||
|
|
@ -34,11 +34,13 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "mnemonic-encoding.h"
|
||||
#include "include_base_utils.h"
|
||||
|
||||
namespace tools
|
||||
{
|
||||
|
|
@ -3371,5 +3373,18 @@ namespace tools
|
|||
}
|
||||
return res;
|
||||
}
|
||||
std::string word_by_num(uint32_t n)
|
||||
{
|
||||
if (n >= NUMWORDS)
|
||||
return "";
|
||||
return wordsArray[n];
|
||||
}
|
||||
|
||||
uint64_t num_by_word(const std::string& w)
|
||||
{
|
||||
auto it = wordsMap.find(w);
|
||||
CHECK_AND_ASSERT_THROW_MES(it!= wordsMap.end(), "unable to find word \"" << w << "\" in mnemonic dictionary");
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,5 +42,7 @@ namespace tools
|
|||
{
|
||||
std::vector<unsigned char> text2binary(const std::string& text);
|
||||
std::string binary2text(const std::vector<unsigned char>& binary);
|
||||
std::string word_by_num(uint32_t n);
|
||||
uint64_t num_by_word(const std::string& w);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "zlib_helper.h"
|
||||
using namespace epee;
|
||||
|
||||
#include "util.h"
|
||||
|
|
@ -526,4 +527,65 @@ std::string get_nix_version_display_string()
|
|||
#endif
|
||||
return std::error_code(code, std::system_category());
|
||||
}
|
||||
|
||||
#define REQUEST_LOG_CHUNK_SIZE_MAX (10 * 1024 * 1024)
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error)
|
||||
{
|
||||
if (size > REQUEST_LOG_CHUNK_SIZE_MAX)
|
||||
{
|
||||
error = std::string("size is exceeding the limit = ") + epee::string_tools::num_to_string_fast(REQUEST_LOG_CHUNK_SIZE_MAX);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
if (std::ifstream log{ log_filename, std::ifstream::ate | std::ifstream::binary })
|
||||
{
|
||||
uint64_t file_size = log.tellg();
|
||||
|
||||
if (offset >= file_size)
|
||||
{
|
||||
error = "offset is out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset + size > file_size)
|
||||
{
|
||||
error = "offset + size if out of bounds";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
log.seekg(offset);
|
||||
output.resize(size);
|
||||
log.read(&output.front(), size);
|
||||
uint64_t read_bytes = log.gcount();
|
||||
if (read_bytes != size)
|
||||
{
|
||||
error = std::string("read bytes: ") + epee::string_tools::num_to_string_fast(read_bytes);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epee::zlib_helper::pack(output))
|
||||
{
|
||||
error = "zlib pack failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
error = std::string("can't open ") + log_filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t get_log_file_size()
|
||||
{
|
||||
std::string log_filename = epee::log_space::log_singletone::get_actual_log_file_path();
|
||||
std::ifstream in(log_filename, std::ifstream::ate | std::ifstream::binary);
|
||||
return static_cast<uint64_t>(in.tellg());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ namespace tools
|
|||
return k;
|
||||
}
|
||||
|
||||
bool get_log_chunk_gzipped(uint64_t offset, uint64_t size, std::string& output, std::string& error);
|
||||
uint64_t get_log_file_size();
|
||||
|
||||
class signal_handler
|
||||
{
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ namespace
|
|||
const command_line::arg_descriptor<std::string> arg_generate_genesis = {"generate-genesis", "Generate genesis coinbase based on config file", "", true };
|
||||
const command_line::arg_descriptor<uint64_t> arg_genesis_split_amount = { "genesis-split-amount", "Set split amount for generating genesis block", 0, true };
|
||||
const command_line::arg_descriptor<std::string> arg_get_info_flags = { "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "", true };
|
||||
const command_line::arg_descriptor<int64_t> arg_set_peer_log_level = { "set-peer-log-level", "Set log level for remote peer", 0, true };
|
||||
const command_line::arg_descriptor<uint64_t> arg_download_peer_log = { "download-peer-log", "Download log from remote peer (starting offset)", 0, true };
|
||||
}
|
||||
|
||||
typedef COMMAND_REQUEST_STAT_INFO_T<t_currency_protocol_handler<core>::stat_info> COMMAND_REQUEST_STAT_INFO;
|
||||
|
|
@ -839,7 +841,166 @@ bool generate_and_print_keys()
|
|||
<< "PRIVATE KEY: " << epee::string_tools::pod_to_hex(sk);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class command_t>
|
||||
bool invoke_debug_command(po::variables_map& vm, const crypto::secret_key& sk, levin::levin_client_impl2& transport, peerid_type& peer_id, typename command_t::request& req, typename command_t::response& rsp)
|
||||
{
|
||||
if (!transport.is_connected())
|
||||
{
|
||||
if (!transport.connect(command_line::get_arg(vm, arg_ip), static_cast<int>(command_line::get_arg(vm, arg_port)), static_cast<int>(command_line::get_arg(vm, arg_timeout))))
|
||||
{
|
||||
std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}" << ENDL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!peer_id)
|
||||
{
|
||||
COMMAND_REQUEST_PEER_ID::request id_req = AUTO_VAL_INIT(id_req);
|
||||
COMMAND_REQUEST_PEER_ID::response id_rsp = AUTO_VAL_INIT(id_rsp);
|
||||
if (!net_utils::invoke_remote_command2(COMMAND_REQUEST_PEER_ID::ID, id_req, id_rsp, transport))
|
||||
{
|
||||
std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}" << ENDL;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
peer_id = id_rsp.my_id;
|
||||
}
|
||||
}
|
||||
|
||||
nodetool::proof_of_trust pot = AUTO_VAL_INIT(pot);
|
||||
pot.peer_id = peer_id;
|
||||
pot.time = time(NULL);
|
||||
crypto::public_key pubk = AUTO_VAL_INIT(pubk);
|
||||
string_tools::hex_to_pod(P2P_MAINTAINERS_PUB_KEY, pubk);
|
||||
crypto::hash h = tools::get_proof_of_trust_hash(pot);
|
||||
crypto::generate_signature(h, pubk, sk, pot.sign);
|
||||
|
||||
req.tr = pot;
|
||||
|
||||
return net_utils::invoke_remote_command2(command_t::ID, req, rsp, transport);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_set_peer_log_level(po::variables_map& vm)
|
||||
{
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
if (!get_private_key(sk, vm))
|
||||
{
|
||||
std::cout << "ERROR: secret key error" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t log_level = command_line::get_arg(vm, arg_set_peer_log_level);
|
||||
if (log_level < LOG_LEVEL_0 || log_level > LOG_LEVEL_MAX)
|
||||
{
|
||||
std::cout << "Error: invalid log level value: " << log_level << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_SET_LOG_LEVEL::request req = AUTO_VAL_INIT(req);
|
||||
req.new_log_level = log_level;
|
||||
|
||||
COMMAND_SET_LOG_LEVEL::response rsp = AUTO_VAL_INIT(rsp);
|
||||
if (!invoke_debug_command<COMMAND_SET_LOG_LEVEL>(vm, sk, transport, peer_id, req, rsp))
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_SET_LOG_LEVEL failed" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "OK! Log level changed: " << rsp.old_log_level << " -> " << rsp.current_log_level << ENDL;
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
bool handle_download_peer_log(po::variables_map& vm)
|
||||
{
|
||||
crypto::secret_key sk = AUTO_VAL_INIT(sk);
|
||||
if (!get_private_key(sk, vm))
|
||||
{
|
||||
std::cout << "ERROR: secret key error" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t start_offset = command_line::get_arg(vm, arg_download_peer_log);
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_REQUEST_LOG::request req = AUTO_VAL_INIT(req);
|
||||
COMMAND_REQUEST_LOG::response rsp = AUTO_VAL_INIT(rsp);
|
||||
if (!invoke_debug_command<COMMAND_REQUEST_LOG>(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty())
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Current log level: " << rsp.current_log_level << ENDL;
|
||||
std::cout << "Current log size: " << rsp.current_log_size << ENDL;
|
||||
|
||||
if (start_offset >= rsp.current_log_size)
|
||||
{
|
||||
std::cout << "ERROR: invalid start offset: " << start_offset << ", log size: " << rsp.current_log_size << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cout << "Downloading..." << ENDL;
|
||||
|
||||
std::string local_filename = tools::get_default_data_dir() + "/log_" + epee::string_tools::num_to_string_fast(peer_id) + ".log";
|
||||
std::ofstream log{ local_filename, std::ifstream::binary };
|
||||
if (!log)
|
||||
{
|
||||
std::cout << "Couldn't open " << local_filename << " for writing." << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint64_t chunk_size = 1024 * 1024 * 5;
|
||||
uint64_t end_offset = start_offset;
|
||||
uint64_t bytes = 0;
|
||||
while (true)
|
||||
{
|
||||
req.log_chunk_offset = end_offset;
|
||||
req.log_chunk_size = std::min(chunk_size, rsp.current_log_size - req.log_chunk_offset);
|
||||
if (req.log_chunk_size == 0)
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
if (!invoke_debug_command<COMMAND_REQUEST_LOG>(vm, sk, transport, peer_id, req, rsp) || !rsp.error.empty())
|
||||
{
|
||||
std::cout << "ERROR: invoking COMMAND_REQUEST_LOG failed: " << rsp.error << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!epee::zlib_helper::unpack(rsp.log_chunk))
|
||||
{
|
||||
std::cout << "ERROR: zip unpack failed" << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rsp.log_chunk.size() != req.log_chunk_size)
|
||||
{
|
||||
std::cout << "ERROR: unpacked size: " << rsp.log_chunk.size() << ", requested: " << req.log_chunk_size << ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
log.write(rsp.log_chunk.c_str(), rsp.log_chunk.size());
|
||||
|
||||
end_offset += req.log_chunk_size;
|
||||
|
||||
std::cout << end_offset - start_offset << " bytes downloaded" << ENDL;
|
||||
}
|
||||
|
||||
std::cout << "Remote log from offset " << start_offset << " to offset " << end_offset << " (" << end_offset - start_offset << " bytes) " <<
|
||||
"was successfully downloaded to " << local_filename;
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
|
|
@ -874,7 +1035,9 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_genesis_split_amount);
|
||||
command_line::add_arg(desc_params, arg_get_info_flags);
|
||||
command_line::add_arg(desc_params, arg_log_journal_len);
|
||||
|
||||
command_line::add_arg(desc_params, arg_set_peer_log_level);
|
||||
command_line::add_arg(desc_params, arg_download_peer_log);
|
||||
|
||||
|
||||
|
||||
po::options_description desc_all;
|
||||
|
|
@ -931,6 +1094,14 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
return generate_genesis(command_line::get_arg(vm, arg_generate_genesis), 10000000000000000) ? 0 : 1;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_set_peer_log_level))
|
||||
{
|
||||
return handle_set_peer_log_level(vm) ? 0 : 1;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_download_peer_log))
|
||||
{
|
||||
return handle_download_peer_log(vm) ? 0 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Not enough arguments." << ENDL;
|
||||
|
|
|
|||
|
|
@ -77,27 +77,16 @@ namespace crypto {
|
|||
memcpy(&res, tmp, 32);
|
||||
}
|
||||
|
||||
void crypto_ops::keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec)
|
||||
void crypto_ops::keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size)
|
||||
{
|
||||
unsigned char tmp[64] = { 0 };
|
||||
static_assert(sizeof tmp >= BRAINWALLET_SHORT_SEED_SIZE, "size mismatch");
|
||||
memcpy(tmp, a_part, BRAINWALLET_SHORT_SEED_SIZE);
|
||||
|
||||
cn_fast_hash(tmp, 16, (char*)&tmp[16]);
|
||||
cn_fast_hash(tmp, 32, (char*)&tmp[32]);
|
||||
if (!(sizeof(tmp) >= brain_wallet_seed_size))
|
||||
{
|
||||
throw std::runtime_error("size mismatch");
|
||||
}
|
||||
|
||||
sc_reduce(tmp);
|
||||
memcpy(&sec, tmp, 32);
|
||||
ge_p3 point;
|
||||
ge_scalarmult_base(&point, &sec);
|
||||
ge_p3_tobytes(&pub, &point);
|
||||
}
|
||||
|
||||
void crypto_ops::keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec)
|
||||
{
|
||||
unsigned char tmp[64] = { 0 };
|
||||
static_assert(sizeof tmp >= BRAINWALLET_DEFAULT_SEED_SIZE, "size mismatch");
|
||||
memcpy(tmp, a_part, BRAINWALLET_DEFAULT_SEED_SIZE);
|
||||
memcpy(tmp, a_part, brain_wallet_seed_size);
|
||||
|
||||
cn_fast_hash(tmp, 32, (char*)&tmp[32]);
|
||||
|
||||
|
|
@ -108,12 +97,14 @@ namespace crypto {
|
|||
ge_p3_tobytes(&pub, &point);
|
||||
}
|
||||
|
||||
void crypto_ops::generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed)
|
||||
void crypto_ops::generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed, size_t brain_wallet_seed_size)
|
||||
{
|
||||
unsigned char tmp[BRAINWALLET_DEFAULT_SEED_SIZE];
|
||||
generate_random_bytes(BRAINWALLET_DEFAULT_SEED_SIZE, tmp);
|
||||
seed.assign((const char*)tmp, BRAINWALLET_DEFAULT_SEED_SIZE);
|
||||
keys_from_default(tmp, pub, sec);
|
||||
std::vector<unsigned char> tmp_vector;
|
||||
tmp_vector.resize(brain_wallet_seed_size, 0);
|
||||
unsigned char *tmp = &tmp_vector[0];
|
||||
generate_random_bytes(brain_wallet_seed_size, tmp);
|
||||
seed.assign((const char*)tmp, brain_wallet_seed_size);
|
||||
keys_from_default(tmp, pub, sec, brain_wallet_seed_size);
|
||||
}
|
||||
|
||||
static inline void hash_to_scalar(const void *data, size_t length, ec_scalar &res)
|
||||
|
|
|
|||
|
|
@ -20,8 +20,6 @@
|
|||
PUSH_WARNINGS
|
||||
DISABLE_CLANG_WARNING(unused-private-field)
|
||||
|
||||
#define BRAINWALLET_DEFAULT_SEED_SIZE 32
|
||||
#define BRAINWALLET_SHORT_SEED_SIZE 16
|
||||
|
||||
namespace crypto {
|
||||
|
||||
|
|
@ -75,12 +73,10 @@ namespace crypto {
|
|||
|
||||
static void generate_keys(public_key &, secret_key &);
|
||||
friend void generate_keys(public_key &, secret_key &);
|
||||
static void generate_brain_keys(public_key &, secret_key &, std::string& seed);
|
||||
friend void generate_brain_keys(public_key &, secret_key &, std::string& seed);
|
||||
static void keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec);
|
||||
friend void keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec);
|
||||
static void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec);
|
||||
friend void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec);
|
||||
static void generate_brain_keys(public_key &, secret_key &, std::string& seed, size_t brain_wallet_seed_size);
|
||||
friend void generate_brain_keys(public_key &, secret_key &, std::string& seed, size_t brain_wallet_seed_size);
|
||||
static void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size);
|
||||
friend void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size);
|
||||
static void dependent_key(const secret_key& first, secret_key& second);
|
||||
friend void dependent_key(const secret_key& first, secret_key& second);
|
||||
static bool check_key(const public_key &);
|
||||
|
|
@ -139,19 +135,14 @@ namespace crypto {
|
|||
crypto_ops::generate_keys(pub, sec);
|
||||
}
|
||||
|
||||
inline void generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed) {
|
||||
crypto_ops::generate_brain_keys(pub, sec, seed);
|
||||
}
|
||||
|
||||
inline void keys_from_short(unsigned char* a_part, public_key &pub, secret_key &sec)
|
||||
{
|
||||
crypto_ops::keys_from_short(a_part, pub, sec);
|
||||
inline void generate_brain_keys(public_key &pub, secret_key &sec, std::string& seed, size_t brain_wallet_seed_size) {
|
||||
crypto_ops::generate_brain_keys(pub, sec, seed, brain_wallet_seed_size);
|
||||
}
|
||||
|
||||
|
||||
inline void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec)
|
||||
inline void keys_from_default(unsigned char* a_part, public_key &pub, secret_key &sec, size_t brain_wallet_seed_size)
|
||||
{
|
||||
crypto_ops::keys_from_default(a_part, pub, sec);
|
||||
crypto_ops::keys_from_default(a_part, pub, sec, brain_wallet_seed_size);
|
||||
}
|
||||
|
||||
inline void dependent_key(const secret_key& first, secret_key& second){
|
||||
|
|
|
|||
|
|
@ -41,9 +41,8 @@ namespace currency
|
|||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::generate()
|
||||
{
|
||||
//generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key);
|
||||
generate_brain_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, m_seed);
|
||||
{
|
||||
generate_brain_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, m_seed, BRAINWALLET_DEFAULT_SEED_SIZE);
|
||||
dependent_key(m_keys.m_spend_secret_key, m_keys.m_view_secret_key);
|
||||
if (!crypto::secret_key_to_public_key(m_keys.m_view_secret_key, m_keys.m_account_address.m_view_public_key))
|
||||
throw std::runtime_error("Failed to create public view key");
|
||||
|
|
@ -62,12 +61,16 @@ namespace currency
|
|||
return m_seed;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
|
||||
std::string account_base::get_restore_braindata() const
|
||||
{
|
||||
std::string restore_buff = get_restore_data();
|
||||
std::vector<unsigned char> v;
|
||||
v.assign((unsigned char*)restore_buff.data(), (unsigned char*)restore_buff.data() + restore_buff.size());
|
||||
return tools::mnemonic_encoding::binary2text(v);
|
||||
std::string seed_brain_data = tools::mnemonic_encoding::binary2text(v);
|
||||
std::string timestamp_word = currency::get_word_from_timstamp(m_creation_timestamp);
|
||||
seed_brain_data = seed_brain_data + timestamp_word;
|
||||
return seed_brain_data;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_keys(const std::string& restore_data)
|
||||
|
|
@ -75,11 +78,7 @@ namespace currency
|
|||
//CHECK_AND_ASSERT_MES(restore_data.size() == ACCOUNT_RESTORE_DATA_SIZE, false, "wrong restore data size");
|
||||
if (restore_data.size() == BRAINWALLET_DEFAULT_SEED_SIZE)
|
||||
{
|
||||
crypto::keys_from_default((unsigned char*)restore_data.data(), m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key);
|
||||
}
|
||||
else if(restore_data.size() == BRAINWALLET_SHORT_SEED_SIZE)
|
||||
{
|
||||
crypto::keys_from_short((unsigned char*)restore_data.data(), m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key);
|
||||
crypto::keys_from_default((unsigned char*)restore_data.data(), m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, BRAINWALLET_DEFAULT_SEED_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -94,15 +93,27 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
bool account_base::restore_keys_from_braindata(const std::string& restore_data)
|
||||
bool account_base::restore_keys_from_braindata(const std::string& restore_data_)
|
||||
{
|
||||
//cut the last timestamp word from restore_dats
|
||||
std::list<std::string> words;
|
||||
boost::split(words, restore_data_, boost::is_space());
|
||||
CHECK_AND_ASSERT_THROW_MES(words.size() == BRAINWALLET_DEFAULT_WORDS_COUNT, "Words count missmatch: " << words.size());
|
||||
|
||||
std::string timestamp_word = words.back();
|
||||
words.erase(--words.end());
|
||||
|
||||
std::string restore_data_local = boost::algorithm::join(words, " ");
|
||||
|
||||
std::vector<unsigned char> bin = tools::mnemonic_encoding::text2binary(restore_data);
|
||||
std::vector<unsigned char> bin = tools::mnemonic_encoding::text2binary(restore_data_local);
|
||||
if (!bin.size())
|
||||
return false;
|
||||
|
||||
std::string restore_buff((const char*)&bin[0], bin.size());
|
||||
return restore_keys(restore_buff);
|
||||
bool r = restore_keys(restore_buff);
|
||||
CHECK_AND_ASSERT_MES(r, false, "restore_keys failed");
|
||||
m_creation_timestamp = get_timstamp_from_word(timestamp_word);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_public_address_str()
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
#include "crypto/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
|
||||
|
||||
#define BRAINWALLET_DEFAULT_SEED_SIZE 32
|
||||
#define ACCOUNT_RESTORE_DATA_SIZE BRAINWALLET_DEFAULT_SEED_SIZE
|
||||
|
||||
#define BRAINWALLET_DEFAULT_WORDS_COUNT 25
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4254,7 +4254,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
|
|||
return false;
|
||||
}
|
||||
|
||||
uint64_t h = get_block_height(bl);
|
||||
get_block_height(bl);
|
||||
|
||||
if(!check_block_timestamp_main(bl))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@
|
|||
#define WALLET_FILE_SIGNATURE 0x1111012101101011LL //Bender's nightmare
|
||||
#define WALLET_FILE_MAX_BODY_SIZE 0x88888888L //2GB
|
||||
#define WALLET_FILE_MAX_KEYS_SIZE 10000 //
|
||||
#define WALLET_BRAIN_DATE_OFFSET 1543622400
|
||||
#define WALLET_BRAIN_DATE_QUANTUM 604800 //by last word we encode a number of week since launch of the project,
|
||||
//which let us to address tools::mnemonic_encoding::NUMWORDS weeks after project launch
|
||||
//which is about 30 years
|
||||
|
||||
#define OFFER_MAXIMUM_LIFE_TIME (60*60*24*30) // 30 days
|
||||
|
||||
|
|
|
|||
|
|
@ -26,54 +26,18 @@ using namespace epee;
|
|||
#include "bc_attachments_helpers.h"
|
||||
#include "genesis.h"
|
||||
#include "genesis_acc.h"
|
||||
#include "common/mnemonic-encoding.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
|
||||
{
|
||||
std::ostringstream s;
|
||||
binary_archive<true> a(s);
|
||||
::serialization::serialize(a, const_cast<transaction_prefix&>(tx));
|
||||
std::string data = s.str();
|
||||
crypto::cn_fast_hash(data.data(), data.size(), h);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_transaction_prefix_hash(tx, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool add_tx_extra_alias(transaction& tx, const extra_alias_entry& alinfo)
|
||||
{
|
||||
tx.extra.push_back(alinfo);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
|
||||
//TODO: validate tx
|
||||
|
||||
//crypto::cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash);
|
||||
get_transaction_prefix_hash(tx, tx_hash);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
/*
|
||||
bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins,
|
||||
|
|
@ -1246,6 +1210,24 @@ namespace currency
|
|||
return reward;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
std::string get_word_from_timstamp(uint64_t timestamp)
|
||||
{
|
||||
uint64_t date_offset = timestamp ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0;
|
||||
uint64_t weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM;
|
||||
CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits<uint32_t>::max(), "internal error: unable to converto to uint32, val = " << weeks_count);
|
||||
uint32_t weeks_count_32 = static_cast<uint32_t>(weeks_count);
|
||||
|
||||
return tools::mnemonic_encoding::word_by_num(weeks_count_32);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_timstamp_from_word(std::string word)
|
||||
{
|
||||
uint64_t count_of_weeks = tools::mnemonic_encoding::num_by_word(word);
|
||||
uint64_t timestamp = count_of_weeks * WALLET_BRAIN_DATE_QUANTUM + WALLET_BRAIN_DATE_OFFSET;
|
||||
|
||||
return timestamp;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed /* = nullptr */)
|
||||
{
|
||||
#define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, msg << ", ms input index: " << ms_input_index << ", tx: " << get_transaction_hash(tx) << ", source tx: " << get_transaction_hash(source_tx))
|
||||
|
|
@ -1620,11 +1602,7 @@ namespace currency
|
|||
att.push_back(tsa);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res)
|
||||
{
|
||||
cn_fast_hash(blob.data(), blob.size(), res);
|
||||
}
|
||||
|
||||
|
||||
std::string print_fixed_decimal_point(uint64_t amount, size_t decimal_point)
|
||||
{
|
||||
|
|
@ -1648,32 +1626,6 @@ namespace currency
|
|||
return std::to_string(amount) + '.' + r.substr(0, r.find_last_not_of('0') + 1);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_blob_hash(const blobdata& blob)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_blob_hash(blob, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_hash(const transaction& t)
|
||||
{
|
||||
return get_transaction_prefix_hash(t);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res)
|
||||
{
|
||||
uint64_t blob_size = 0;
|
||||
return get_object_hash(static_cast<const transaction_prefix&>(t), res, blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, uint64_t& blob_size)
|
||||
{
|
||||
blob_size = 0;
|
||||
bool r = get_object_hash(static_cast<const transaction_prefix&>(t), res, blob_size);
|
||||
blob_size = get_object_blobsize(t, blob_size);
|
||||
return r;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
/*bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size)
|
||||
{
|
||||
|
||||
|
|
@ -1926,27 +1878,6 @@ namespace currency
|
|||
return ss.str();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata get_block_hashing_blob(const block& b)
|
||||
{
|
||||
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
|
||||
crypto::hash tree_root_hash = get_tx_tree_hash(b);
|
||||
blob.append((const char*)&tree_root_hash, sizeof(tree_root_hash));
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size() + 1));
|
||||
return blob;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_hash(const block& b, crypto::hash& res)
|
||||
{
|
||||
return get_object_hash(get_block_hashing_blob(b), res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_block_hash(const block& b)
|
||||
{
|
||||
crypto::hash p = null_hash;
|
||||
get_block_hash(b, p);
|
||||
return p;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_genesis_block(block& bl)
|
||||
{
|
||||
//genesis block
|
||||
|
|
@ -2052,101 +1983,9 @@ namespace currency
|
|||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
|
||||
{
|
||||
return t_unserializable_object_from_blob(b, b_blob);
|
||||
return parse_and_validate_object_from_blob(b_blob, b);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t)
|
||||
{
|
||||
size_t tx_blob_size = get_object_blobsize(static_cast<const transaction_prefix&>(t));
|
||||
return get_object_blobsize(t, tx_blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size)
|
||||
{
|
||||
size_t tx_blob_size = prefix_blob_size;
|
||||
|
||||
if (is_coinbase(t))
|
||||
return tx_blob_size;
|
||||
|
||||
// for purged tx, with empty signatures and attachments, this function should return the blob size
|
||||
// which the tx would have if the signatures and attachments were correctly filled with actual data
|
||||
|
||||
// 1. signatures
|
||||
bool separately_signed_tx = get_tx_flags(t) & TX_FLAG_SIGNATURE_MODE_SEPARATE;
|
||||
|
||||
tx_blob_size += tools::get_varint_packed_size(t.vin.size()); // size of transaction::signatures (equals to total inputs count)
|
||||
|
||||
for (size_t i = 0; i != t.vin.size(); i++)
|
||||
{
|
||||
size_t sig_count = get_input_expected_signatures_count(t.vin[i]);
|
||||
if (separately_signed_tx && i == t.vin.size() - 1)
|
||||
++sig_count; // count in one more signature for the last input in a complete separately signed tx
|
||||
tx_blob_size += tools::get_varint_packed_size(sig_count); // size of transaction::signatures[i]
|
||||
tx_blob_size += sizeof(crypto::signature) * sig_count; // size of signatures' data itself
|
||||
}
|
||||
|
||||
// 2. attachments (try to find extra_attachment_info in tx prefix and count it in if succeed)
|
||||
extra_attachment_info eai = AUTO_VAL_INIT(eai);
|
||||
bool got_eai = false;
|
||||
if (separately_signed_tx)
|
||||
{
|
||||
// for separately-signed tx, try to obtain extra_attachment_info from the last input's etc_details
|
||||
const std::vector<txin_etc_details_v>* p_etc_details = get_input_etc_details(t.vin.back());
|
||||
got_eai = p_etc_details != nullptr && get_type_in_variant_container(*p_etc_details, eai);
|
||||
}
|
||||
if (!got_eai)
|
||||
got_eai = get_type_in_variant_container(t.extra, eai); // then from the extra
|
||||
|
||||
if (got_eai)
|
||||
tx_blob_size += eai.sz; // sz is a size of whole serialized attachment blob, including attachments vector size
|
||||
else
|
||||
tx_blob_size += tools::get_varint_packed_size(static_cast<size_t>(0)); // no extra_attachment_info found - just add zero vector's size, 'cause it's serialized anyway
|
||||
|
||||
return tx_blob_size;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata block_to_blob(const block& b)
|
||||
{
|
||||
return t_serializable_object_to_blob(b);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool block_to_blob(const block& b, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(b, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata tx_to_blob(const transaction& tx)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool tx_to_blob(const transaction& tx, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h)
|
||||
{
|
||||
tree_hash(tx_hashes.data(), tx_hashes.size(), h);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_tx_tree_hash(tx_hashes, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_tx_tree_hash(const block& b)
|
||||
{
|
||||
std::vector<crypto::hash> txs_ids;
|
||||
crypto::hash h = null_hash;
|
||||
get_transaction_hash(b.miner_tx, h);
|
||||
txs_ids.push_back(h);
|
||||
BOOST_FOREACH(auto& th, b.tx_hashes)
|
||||
txs_ids.push_back(th);
|
||||
return get_tx_tree_hash(txs_ids);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_service_tx(const transaction& tx)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,10 +11,12 @@
|
|||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "currency_protocol/currency_protocol_defs.h"
|
||||
|
||||
#include "account.h"
|
||||
#include "include_base_utils.h"
|
||||
|
||||
#include "currency_format_utils_abstract.h"
|
||||
#include "common/crypto_stream_operators.h"
|
||||
#include "currency_protocol/currency_protocol_defs.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "difficulty.h"
|
||||
|
|
@ -23,6 +25,8 @@
|
|||
#include "bc_payments_id_service.h"
|
||||
#include "bc_attachments_helpers_basic.h"
|
||||
#include "blockchain_storage_basic.h"
|
||||
#include "currency_format_utils_blocks.h"
|
||||
#include "currency_format_utils_transactions.h"
|
||||
|
||||
// ------ get_tx_type_definition -------------
|
||||
#define GUI_TX_TYPE_NORMAL 0
|
||||
|
|
@ -42,31 +46,8 @@
|
|||
|
||||
|
||||
|
||||
//------
|
||||
bool parse_hash256(const std::string str_hash, crypto::hash& hash);
|
||||
template <class T>
|
||||
std::ostream &print256(std::ostream &o, const T &v) {
|
||||
return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::ostream &print16(std::ostream &o, const T &v) {
|
||||
return o << "<" << epee::string_tools::pod_to_hex(v).substr(0, 5) << "..>";
|
||||
}
|
||||
|
||||
template <class T>
|
||||
std::string print16(const T &v) {
|
||||
return std::string("<") + epee::string_tools::pod_to_hex(v).substr(0, 5) + "..>";
|
||||
}
|
||||
|
||||
namespace crypto {
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); }
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); }
|
||||
}
|
||||
|
||||
namespace currency
|
||||
{
|
||||
|
|
@ -182,10 +163,6 @@ namespace currency
|
|||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
|
||||
bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins,
|
||||
size_t current_block_size,
|
||||
uint64_t fee,
|
||||
|
|
@ -234,14 +211,6 @@ namespace currency
|
|||
|
||||
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median);
|
||||
|
||||
template<class t_type>
|
||||
std::string print_t_array(const std::vector<t_type>& vec)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for (auto& v : vec)
|
||||
ss << v << " ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
uint64_t get_string_uint64_hash(const std::string& str);
|
||||
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
|
||||
|
|
@ -302,8 +271,6 @@ namespace currency
|
|||
bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki);
|
||||
bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key, crypto::key_derivation& derivation);
|
||||
bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key);
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res);
|
||||
crypto::hash get_blob_hash(const blobdata& blob);
|
||||
std::string short_hash_str(const crypto::hash& h);
|
||||
bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_attr_count);
|
||||
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time);
|
||||
|
|
@ -316,13 +283,7 @@ namespace currency
|
|||
|
||||
uint64_t get_reward_from_miner_tx(const transaction& tx);
|
||||
|
||||
crypto::hash get_transaction_hash(const transaction& t);
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res);
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, uint64_t& blob_size);
|
||||
//bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size);
|
||||
blobdata get_block_hashing_blob(const block& b);
|
||||
bool get_block_hash(const block& b, crypto::hash& res);
|
||||
crypto::hash get_block_hash(const block& b);
|
||||
bool generate_genesis_block(block& bl);
|
||||
const crypto::hash& get_genesis_hash(bool need_to_set = false, const crypto::hash& h = null_hash);
|
||||
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
|
||||
|
|
@ -389,18 +350,8 @@ namespace currency
|
|||
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false);
|
||||
bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h);
|
||||
void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map<uint64_t, uint32_t>& gindices);
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<class t_array>
|
||||
struct array_hasher : std::unary_function<t_array&, std::size_t>
|
||||
{
|
||||
std::size_t operator()(const t_array& val) const
|
||||
{
|
||||
return boost::hash_range(&val.data[0], &val.data[sizeof(val.data)]);
|
||||
}
|
||||
};
|
||||
std::string get_word_from_timstamp(uint64_t timestamp);
|
||||
uint64_t get_timstamp_from_word(std::string word);
|
||||
|
||||
template<class t_txin_v>
|
||||
typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type& get_txin_etc_options(t_txin_v& in)
|
||||
|
|
@ -450,17 +401,6 @@ namespace currency
|
|||
bool have_attachment_service_in_container(const std::vector<attachment_v>& av, const std::string& service_id, const std::string& instruction);
|
||||
crypto::hash prepare_prefix_hash_for_sign(const transaction& tx, uint64_t in_index, const crypto::hash& tx_id);
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
template<class t_pod_type, class result_type>
|
||||
result_type get_pod_checksum(const t_pod_type& bl)
|
||||
{
|
||||
const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
|
||||
result_type summ = 0;
|
||||
for (size_t i = 0; i != sizeof(t_pod_type)-1; i++)
|
||||
summ += pbuf[i];
|
||||
|
||||
return summ;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class tx_out_t>
|
||||
bool is_out_to_acc(const account_keys& acc, const tx_out_t& out_key, const crypto::public_key& tx_pub_key, size_t output_index)
|
||||
|
|
@ -469,83 +409,6 @@ namespace currency
|
|||
generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
|
||||
return is_out_to_acc(acc, out_key, derivation, output_index);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specic_type_t, typename variant_t_container>
|
||||
bool have_type_in_variant_container(const variant_t_container& av)
|
||||
{
|
||||
for (auto& ai : av)
|
||||
{
|
||||
if (ai.type() == typeid(specic_type_t))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specic_type_t, typename variant_t_container>
|
||||
size_t count_type_in_variant_container(const variant_t_container& av)
|
||||
{
|
||||
size_t result = 0;
|
||||
for (auto& ai : av)
|
||||
{
|
||||
if (ai.type() == typeid(specic_type_t))
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specic_type_t, typename variant_t_container>
|
||||
bool get_type_in_variant_container(const variant_t_container& av, specic_type_t& a)
|
||||
{
|
||||
for (auto& ai : av)
|
||||
{
|
||||
if (ai.type() == typeid(specic_type_t))
|
||||
{
|
||||
a = boost::get<specic_type_t>(ai);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename variant_container_t>
|
||||
bool check_allowed_types_in_variant_container(const variant_container_t& container, const std::unordered_set<std::type_index>& allowed_types, bool elements_must_be_unique = true)
|
||||
{
|
||||
for (auto it = container.begin(); it != container.end(); ++it)
|
||||
{
|
||||
if (allowed_types.count(std::type_index(it->type())) == 0)
|
||||
return false;
|
||||
|
||||
if (elements_must_be_unique)
|
||||
{
|
||||
for (auto jt = it + 1; jt != container.end(); ++jt)
|
||||
if (it->type().hash_code() == jt->type().hash_code())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename variant_container_t>
|
||||
bool check_allowed_types_in_variant_container(const variant_container_t& container, const variant_container_t& allowed_types_examples, bool elements_must_be_unique = true)
|
||||
{
|
||||
std::unordered_set<std::type_index> allowed_types;
|
||||
for (auto& el : allowed_types_examples)
|
||||
if (!allowed_types.insert(std::type_index(el.type())).second)
|
||||
return false; // invalid allowed_types_examples container
|
||||
|
||||
return check_allowed_types_in_variant_container(container, allowed_types, elements_must_be_unique);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename variant_container_t>
|
||||
std::string stringize_types_in_variant_container(const variant_container_t& container)
|
||||
{
|
||||
std::string result;
|
||||
for (auto it = container.begin(); it != container.end(); ++it)
|
||||
result = (result + it->type().name()) + (it + 1 != container.end() ? ", " : "");
|
||||
return result;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
template<class t_container>
|
||||
bool validate_attachment_info(const t_container& container, const std::vector<attachment_v>& attachments, bool allow_no_info_for_non_empty_attachments_container)
|
||||
|
|
@ -692,51 +555,7 @@ namespace currency
|
|||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool get_object_hash(const t_object& o, crypto::hash& res)
|
||||
{
|
||||
get_blob_hash(t_serializable_object_to_blob(o), res);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
crypto::hash get_object_hash(const t_object& o)
|
||||
{
|
||||
crypto::hash h;
|
||||
get_object_hash(o, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
template<class t_object>
|
||||
size_t get_object_blobsize(const t_object& o)
|
||||
{
|
||||
blobdata b = t_serializable_object_to_blob(o);
|
||||
return b.size();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t);
|
||||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size);
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool get_object_hash(const t_object& o, crypto::hash& res, uint64_t& blob_size)
|
||||
{
|
||||
blobdata bl = t_serializable_object_to_blob(o);
|
||||
blob_size = bl.size();
|
||||
get_blob_hash(bl, res);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename T>
|
||||
std::string obj_to_json_str(const T& obj)
|
||||
{
|
||||
std::stringstream ss;
|
||||
json_archive<true> ar(ss, true);
|
||||
bool r = ::serialization::serialize(ar, const_cast<T&>(obj));
|
||||
CHECK_AND_ASSERT_MES(r, "", "obj_to_json_str failed: serialization::serialize returned false");
|
||||
return ss.str();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// 62387455827 -> 455827 + 7000000 + 80000000 + 300000000 + 2000000000 + 60000000000, where 455827 <= dust_threshold
|
||||
template<typename chunk_handler_t, typename dust_handler_t>
|
||||
|
|
@ -843,18 +662,6 @@ namespace currency
|
|||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
blobdata block_to_blob(const block& b);
|
||||
bool block_to_blob(const block& b, blobdata& b_blob);
|
||||
blobdata tx_to_blob(const transaction& b);
|
||||
bool tx_to_blob(const transaction& b, blobdata& b_blob);
|
||||
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h);
|
||||
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes);
|
||||
crypto::hash get_tx_tree_hash(const block& b);
|
||||
|
||||
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \
|
||||
CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \
|
||||
specific_type& variable_name = boost::get<specific_type>(variant_var);
|
||||
|
||||
struct input_amount_getter : public boost::static_visitor<uint64_t>
|
||||
{
|
||||
template<class t_input>
|
||||
|
|
@ -866,7 +673,6 @@ namespace currency
|
|||
{
|
||||
return boost::apply_visitor(input_amount_getter(), v);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
std::ostream& operator <<(std::ostream& o, const ref_by_id& r);
|
||||
//---------------------------------------------------------------
|
||||
|
|
|
|||
218
src/currency_core/currency_format_utils_abstract.h
Normal file
218
src/currency_core/currency_format_utils_abstract.h
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
// 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 <typeindex>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include "storages/portable_storage_template_helper.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "currency_protocol/blobdatatype.h"
|
||||
#include "common/crypto_stream_operators.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
|
||||
template<typename type_t>
|
||||
std::string print_kv_structure(const type_t& v)
|
||||
{
|
||||
return epee::serialization::store_t_to_json(v);
|
||||
}
|
||||
|
||||
template<class t_type>
|
||||
std::string print_t_array(const std::vector<t_type>& vec)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for (auto& v : vec)
|
||||
ss << v << " ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<class t_array>
|
||||
struct array_hasher : std::unary_function<t_array&, std::size_t>
|
||||
{
|
||||
std::size_t operator()(const t_array& val) const
|
||||
{
|
||||
return boost::hash_range(&val.data[0], &val.data[sizeof(val.data)]);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------------
|
||||
template<class t_pod_type, class result_type>
|
||||
result_type get_pod_checksum(const t_pod_type& bl)
|
||||
{
|
||||
const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
|
||||
result_type summ = 0;
|
||||
for (size_t i = 0; i != sizeof(t_pod_type)-1; i++)
|
||||
summ += pbuf[i];
|
||||
|
||||
return summ;
|
||||
}
|
||||
|
||||
template<typename object_t>
|
||||
bool parse_and_validate_object_from_blob(const blobdata& b_blob, object_t& b)
|
||||
{
|
||||
return t_unserializable_object_from_blob(b, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specic_type_t, typename variant_t_container>
|
||||
bool have_type_in_variant_container(const variant_t_container& av)
|
||||
{
|
||||
for (auto& ai : av)
|
||||
{
|
||||
if (ai.type() == typeid(specic_type_t))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specic_type_t, typename variant_t_container>
|
||||
size_t count_type_in_variant_container(const variant_t_container& av)
|
||||
{
|
||||
size_t result = 0;
|
||||
for (auto& ai : av)
|
||||
{
|
||||
if (ai.type() == typeid(specic_type_t))
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specic_type_t, typename variant_t_container>
|
||||
bool get_type_in_variant_container(const variant_t_container& av, specic_type_t& a)
|
||||
{
|
||||
for (auto& ai : av)
|
||||
{
|
||||
if (ai.type() == typeid(specic_type_t))
|
||||
{
|
||||
a = boost::get<specic_type_t>(ai);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename variant_container_t>
|
||||
bool check_allowed_types_in_variant_container(const variant_container_t& container, const std::unordered_set<std::type_index>& allowed_types, bool elements_must_be_unique = true)
|
||||
{
|
||||
for (auto it = container.begin(); it != container.end(); ++it)
|
||||
{
|
||||
if (allowed_types.count(std::type_index(it->type())) == 0)
|
||||
return false;
|
||||
|
||||
if (elements_must_be_unique)
|
||||
{
|
||||
for (auto jt = it + 1; jt != container.end(); ++jt)
|
||||
if (it->type().hash_code() == jt->type().hash_code())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename variant_container_t>
|
||||
bool check_allowed_types_in_variant_container(const variant_container_t& container, const variant_container_t& allowed_types_examples, bool elements_must_be_unique = true)
|
||||
{
|
||||
std::unordered_set<std::type_index> allowed_types;
|
||||
for (auto& el : allowed_types_examples)
|
||||
if (!allowed_types.insert(std::type_index(el.type())).second)
|
||||
return false; // invalid allowed_types_examples container
|
||||
|
||||
return check_allowed_types_in_variant_container(container, allowed_types, elements_must_be_unique);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename variant_container_t>
|
||||
std::string stringize_types_in_variant_container(const variant_container_t& container)
|
||||
{
|
||||
std::string result;
|
||||
for (auto it = container.begin(); it != container.end(); ++it)
|
||||
result = (result + it->type().name()) + (it + 1 != container.end() ? ", " : "");
|
||||
return result;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
inline
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res)
|
||||
{
|
||||
cn_fast_hash(blob.data(), blob.size(), res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
inline
|
||||
crypto::hash get_blob_hash(const blobdata& blob)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_blob_hash(blob, h);
|
||||
return h;
|
||||
}
|
||||
|
||||
template<class t_object>
|
||||
bool get_object_hash(const t_object& o, crypto::hash& res)
|
||||
{
|
||||
get_blob_hash(t_serializable_object_to_blob(o), res);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
crypto::hash get_object_hash(const t_object& o)
|
||||
{
|
||||
crypto::hash h;
|
||||
get_object_hash(o, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
template<class t_object>
|
||||
size_t get_object_blobsize(const t_object& o)
|
||||
{
|
||||
blobdata b = t_serializable_object_to_blob(o);
|
||||
return b.size();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class t_object>
|
||||
bool get_object_hash(const t_object& o, crypto::hash& res, uint64_t& blob_size)
|
||||
{
|
||||
blobdata bl = t_serializable_object_to_blob(o);
|
||||
blob_size = bl.size();
|
||||
get_blob_hash(bl, res);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename T>
|
||||
std::string obj_to_json_str(const T& obj)
|
||||
{
|
||||
std::stringstream ss;
|
||||
json_archive<true> ar(ss, true);
|
||||
bool r = ::serialization::serialize(ar, const_cast<T&>(obj));
|
||||
CHECK_AND_ASSERT_MES(r, "", "obj_to_json_str failed: serialization::serialize returned false");
|
||||
return ss.str();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t);
|
||||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size);
|
||||
|
||||
|
||||
|
||||
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \
|
||||
CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \
|
||||
specific_type& variable_name = boost::get<specific_type>(variant_var);
|
||||
|
||||
} // namespace currency
|
||||
|
||||
|
||||
|
||||
67
src/currency_core/currency_format_utils_blocks.cpp
Normal file
67
src/currency_core/currency_format_utils_blocks.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// 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 "currency_format_utils_blocks.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "currency_format_utils_abstract.h"
|
||||
#include "currency_format_utils_transactions.h"
|
||||
namespace currency
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
blobdata get_block_hashing_blob(const block& b)
|
||||
{
|
||||
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
|
||||
crypto::hash tree_root_hash = get_tx_tree_hash(b);
|
||||
blob.append((const char*)&tree_root_hash, sizeof(tree_root_hash));
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size() + 1));
|
||||
return blob;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_block_hash(const block& b, crypto::hash& res)
|
||||
{
|
||||
return get_object_hash(get_block_hashing_blob(b), res);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_block_hash(const block& b)
|
||||
{
|
||||
crypto::hash p = null_hash;
|
||||
get_block_hash(b, p);
|
||||
return p;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata block_to_blob(const block& b)
|
||||
{
|
||||
return t_serializable_object_to_blob(b);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool block_to_blob(const block& b, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(b, b_blob);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h)
|
||||
{
|
||||
tree_hash(tx_hashes.data(), tx_hashes.size(), h);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_tx_tree_hash(tx_hashes, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_tx_tree_hash(const block& b)
|
||||
{
|
||||
std::vector<crypto::hash> txs_ids;
|
||||
crypto::hash h = null_hash;
|
||||
get_transaction_hash(b.miner_tx, h);
|
||||
txs_ids.push_back(h);
|
||||
BOOST_FOREACH(auto& th, b.tx_hashes)
|
||||
txs_ids.push_back(th);
|
||||
return get_tx_tree_hash(txs_ids);
|
||||
}
|
||||
}
|
||||
25
src/currency_core/currency_format_utils_blocks.h
Normal file
25
src/currency_core/currency_format_utils_blocks.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// 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 "crypto/crypto.h"
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "currency_protocol/blobdatatype.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
blobdata get_block_hashing_blob(const block& b);
|
||||
bool get_block_hash(const block& b, crypto::hash& res);
|
||||
crypto::hash get_block_hash(const block& b);
|
||||
|
||||
blobdata block_to_blob(const block& b);
|
||||
bool block_to_blob(const block& b, blobdata& b_blob);
|
||||
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h);
|
||||
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes);
|
||||
crypto::hash get_tx_tree_hash(const block& b);
|
||||
|
||||
}
|
||||
134
src/currency_core/currency_format_utils_transactions.cpp
Normal file
134
src/currency_core/currency_format_utils_transactions.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// 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 "currency_format_utils_transactions.h"
|
||||
#include "serialization/serialization.h"
|
||||
#include "currency_format_utils_abstract.h"
|
||||
#include "currency_format_utils.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
|
||||
{
|
||||
std::ostringstream s;
|
||||
binary_archive<true> a(s);
|
||||
::serialization::serialize(a, const_cast<transaction_prefix&>(tx));
|
||||
std::string data = s.str();
|
||||
crypto::cn_fast_hash(data.data(), data.size(), h);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_transaction_prefix_hash(tx, h);
|
||||
return h;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << tx_blob;
|
||||
binary_archive<false> ba(ss);
|
||||
bool r = ::serialization::serialize(ba, tx);
|
||||
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
|
||||
//TODO: validate tx
|
||||
|
||||
//crypto::cn_fast_hash(tx_blob.data(), tx_blob.size(), tx_hash);
|
||||
get_transaction_prefix_hash(tx, tx_hash);
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_hash(const transaction& t)
|
||||
{
|
||||
return get_transaction_prefix_hash(t);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res)
|
||||
{
|
||||
uint64_t blob_size = 0;
|
||||
return get_object_hash(static_cast<const transaction_prefix&>(t), res, blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool get_transaction_hash(const transaction& t, crypto::hash& res, uint64_t& blob_size)
|
||||
{
|
||||
blob_size = 0;
|
||||
bool r = get_object_hash(static_cast<const transaction_prefix&>(t), res, blob_size);
|
||||
blob_size = get_object_blobsize(t, blob_size);
|
||||
return r;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t)
|
||||
{
|
||||
size_t tx_blob_size = get_object_blobsize(static_cast<const transaction_prefix&>(t));
|
||||
return get_object_blobsize(t, tx_blob_size);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size)
|
||||
{
|
||||
size_t tx_blob_size = prefix_blob_size;
|
||||
|
||||
if (is_coinbase(t))
|
||||
return tx_blob_size;
|
||||
|
||||
// for purged tx, with empty signatures and attachments, this function should return the blob size
|
||||
// which the tx would have if the signatures and attachments were correctly filled with actual data
|
||||
|
||||
// 1. signatures
|
||||
bool separately_signed_tx = get_tx_flags(t) & TX_FLAG_SIGNATURE_MODE_SEPARATE;
|
||||
|
||||
tx_blob_size += tools::get_varint_packed_size(t.vin.size()); // size of transaction::signatures (equals to total inputs count)
|
||||
|
||||
for (size_t i = 0; i != t.vin.size(); i++)
|
||||
{
|
||||
size_t sig_count = get_input_expected_signatures_count(t.vin[i]);
|
||||
if (separately_signed_tx && i == t.vin.size() - 1)
|
||||
++sig_count; // count in one more signature for the last input in a complete separately signed tx
|
||||
tx_blob_size += tools::get_varint_packed_size(sig_count); // size of transaction::signatures[i]
|
||||
tx_blob_size += sizeof(crypto::signature) * sig_count; // size of signatures' data itself
|
||||
}
|
||||
|
||||
// 2. attachments (try to find extra_attachment_info in tx prefix and count it in if succeed)
|
||||
extra_attachment_info eai = AUTO_VAL_INIT(eai);
|
||||
bool got_eai = false;
|
||||
if (separately_signed_tx)
|
||||
{
|
||||
// for separately-signed tx, try to obtain extra_attachment_info from the last input's etc_details
|
||||
const std::vector<txin_etc_details_v>* p_etc_details = get_input_etc_details(t.vin.back());
|
||||
got_eai = p_etc_details != nullptr && get_type_in_variant_container(*p_etc_details, eai);
|
||||
}
|
||||
if (!got_eai)
|
||||
got_eai = get_type_in_variant_container(t.extra, eai); // then from the extra
|
||||
|
||||
if (got_eai)
|
||||
tx_blob_size += eai.sz; // sz is a size of whole serialized attachment blob, including attachments vector size
|
||||
else
|
||||
tx_blob_size += tools::get_varint_packed_size(static_cast<size_t>(0)); // no extra_attachment_info found - just add zero vector's size, 'cause it's serialized anyway
|
||||
|
||||
return tx_blob_size;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
blobdata tx_to_blob(const transaction& tx)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool tx_to_blob(const transaction& tx, blobdata& b_blob)
|
||||
{
|
||||
return t_serializable_object_to_blob(tx, b_blob);
|
||||
}
|
||||
|
||||
}
|
||||
27
src/currency_core/currency_format_utils_transactions.h
Normal file
27
src/currency_core/currency_format_utils_transactions.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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 "crypto/crypto.h"
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "currency_protocol/blobdatatype.h"
|
||||
|
||||
|
||||
namespace currency
|
||||
{
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash);
|
||||
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
|
||||
crypto::hash get_transaction_hash(const transaction& t);
|
||||
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_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);
|
||||
}
|
||||
|
|
@ -184,7 +184,9 @@ namespace currency {
|
|||
return (low + time_span - 1) / time_span;
|
||||
}
|
||||
|
||||
wide_difficulty_type next_difficulty(vector<uint64_t> timestamps, vector<wide_difficulty_type> cumulative_difficulties, size_t target_seconds) {
|
||||
wide_difficulty_type next_difficulty(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
{
|
||||
// timestamps - first is latest, back - is oldest timestamps
|
||||
//cutoff DIFFICULTY_LAG
|
||||
if(timestamps.size() > DIFFICULTY_WINDOW)
|
||||
{
|
||||
|
|
@ -210,7 +212,7 @@ namespace currency {
|
|||
cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2;
|
||||
cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT);
|
||||
}
|
||||
assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length);
|
||||
CHECK_AND_ASSERT_THROW_MES(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length, "validation in next_difficulty is failed");
|
||||
uint64_t time_span = timestamps[cut_begin] - timestamps[cut_end - 1];
|
||||
if (time_span == 0) {
|
||||
time_span = 1;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace currency
|
|||
difficulty_type next_difficulty_old(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
|
||||
|
||||
bool check_hash(const crypto::hash &hash, wide_difficulty_type difficulty);
|
||||
wide_difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<wide_difficulty_type> cumulative_difficulties, size_t target_seconds);
|
||||
wide_difficulty_type next_difficulty(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
|
||||
uint64_t difficulty_to_boundary(wide_difficulty_type difficulty);
|
||||
void difficulty_to_boundary_long(wide_difficulty_type difficulty, crypto::hash& result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ namespace currency
|
|||
{
|
||||
std::list<blobdata> txs;
|
||||
std::list<block_complete_entry> blocks;
|
||||
std::list<crypto::hash> missed_ids;
|
||||
std::list<crypto::hash> missed_ids;
|
||||
uint64_t current_blockchain_height;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
|
|
@ -168,3 +168,5 @@ namespace currency
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
#include "currency_protocol_defs_print.h"
|
||||
|
|
|
|||
89
src/currency_protocol/currency_protocol_defs_print.h
Normal file
89
src/currency_protocol/currency_protocol_defs_print.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright (c) 2014-2018 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 "currency_core/currency_format_utils_abstract.h"
|
||||
#include "currency_core/currency_format_utils_blocks.h"
|
||||
#include "storages/portable_storage_to_json.h"
|
||||
|
||||
namespace currency
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
inline std::string print_complete_block_entry_list(const std::list<block_complete_entry>& blocks)
|
||||
{
|
||||
std::stringstream ss;
|
||||
size_t i = 0;
|
||||
for (const block_complete_entry& block_entry : blocks)
|
||||
{
|
||||
ss << "[" << i << "]";
|
||||
block b = AUTO_VAL_INIT(b);
|
||||
if (!parse_and_validate_object_from_blob(block_entry.block, b))
|
||||
{
|
||||
ss << "UNPARSED" << ENDL;
|
||||
}
|
||||
ss << get_block_hash(b) << "{....parent: " << b.prev_id << "....}" << ENDL;
|
||||
|
||||
i++;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<typename container_t>
|
||||
std::string print_container_of_hashs(const container_t& cont, size_t indent)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::string indent_str(indent, ' ');
|
||||
for (const auto& h : cont)
|
||||
{
|
||||
ss << indent_str << h << ENDL;
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline
|
||||
std::string print_kv_structure(const NOTIFY_REQUEST_GET_OBJECTS::request& v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "blocks: {" << ENDL << print_container_of_hashs(v.blocks, 2) << ENDL << "}";
|
||||
ss << "txs: {" << ENDL << print_container_of_hashs(v.txs, 2) << ENDL << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline
|
||||
std::string print_kv_structure(const NOTIFY_RESPONSE_GET_OBJECTS::request& v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "\"blocks\":{" << ENDL << print_complete_block_entry_list(v.blocks) << ENDL << "}, " << ENDL;
|
||||
ss << "\"missed_ids\":" << ENDL;
|
||||
::epee::serialization::dump_as_json(ss, v.missed_ids, 2);
|
||||
ss << ENDL << "\"current_blockchain_height\":" << v.current_blockchain_height;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
inline
|
||||
std::string print_kv_structure(const NOTIFY_REQUEST_CHAIN::request& v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
size_t i = 0;
|
||||
ss << "block_ids: {" << ENDL << print_container_of_hashs(v.block_ids, 2) << ENDL << "}";
|
||||
return ss.str();
|
||||
}
|
||||
inline
|
||||
std::string print_kv_structure(const NOTIFY_RESPONSE_CHAIN_ENTRY::request& v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "start_height:" << v.start_height << ENDL;
|
||||
ss << "total_height:" << v.total_height << ENDL;
|
||||
ss << "block_ids: {" << ENDL;
|
||||
for (const block_context_info& bei : v.m_block_ids)
|
||||
{
|
||||
ss << bei.h << ":" << bei.cumul_size << ENDL;
|
||||
}
|
||||
ss << "}";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Copyright (c) 2014-2018 The Louisdor Project
|
||||
// Copyright (c) 2012-2013 The Cryptonote developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
|
|
@ -70,6 +70,8 @@ namespace currency
|
|||
{
|
||||
NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
|
||||
m_core.get_short_chain_history(r.block_ids);
|
||||
LOG_PRINT_L2("[NOTIFY]NOTIFY_REQUEST_CHAIN(on_callback): m_block_ids.size()=" << r.block_ids.size());
|
||||
LOG_PRINT_L3("[NOTIFY]NOTIFY_REQUEST_CHAIN(on_callback): " << ENDL << print_kv_structure(r));
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
}
|
||||
|
||||
|
|
@ -308,7 +310,8 @@ namespace currency
|
|||
NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
|
||||
m_core.get_short_chain_history(r.block_ids);
|
||||
LOG_PRINT_MAGENTA("State changed to state_synchronizing.", LOG_LEVEL_2);
|
||||
LOG_PRINT_L2("[REQUEST]NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
LOG_PRINT_L2("[NOTIFY]NOTIFY_REQUEST_CHAIN(on_orphaned): m_block_ids.size()=" << r.block_ids.size() );
|
||||
LOG_PRINT_L3("[NOTIFY]NOTIFY_REQUEST_CHAIN(on_orphaned): " << ENDL << print_kv_structure(r));
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
}
|
||||
|
||||
|
|
@ -355,6 +358,9 @@ namespace currency
|
|||
template<class t_core>
|
||||
int t_currency_protocol_handler<t_core>::handle_request_get_objects(int command, NOTIFY_REQUEST_GET_OBJECTS::request& arg, currency_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_L2("[HANDLE]NOTIFY_REQUEST_GET_OBJECTS: arg.blocks.size() = " << arg.blocks.size() << ", arg.txs.size()="<< arg.txs.size());
|
||||
LOG_PRINT_L3("[HANDLE]NOTIFY_REQUEST_GET_OBJECTS: " << ENDL << currency::print_kv_structure(arg));
|
||||
|
||||
if (arg.blocks.size() > CURRENCY_PROTOCOL_MAX_BLOCKS_REQUEST_COUNT)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Requested objects count is to big (" << arg.blocks.size() <<")expected not more then " << CURRENCY_PROTOCOL_MAX_BLOCKS_REQUEST_COUNT);
|
||||
|
|
@ -367,8 +373,12 @@ namespace currency
|
|||
LOG_ERROR_CCONTEXT("failed to handle request NOTIFY_REQUEST_GET_OBJECTS, dropping connection");
|
||||
m_p2p->drop_connection(context);
|
||||
}
|
||||
LOG_PRINT_L2("[HANDLE]NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size()
|
||||
|
||||
LOG_PRINT_L2("[NOTIFY]NOTIFY_RESPONSE_GET_OBJECTS: blocks.size()=" << rsp.blocks.size() << ", txs.size()=" << rsp.txs.size()
|
||||
<< ", rsp.m_current_blockchain_height=" << rsp.current_blockchain_height << ", missed_ids.size()=" << rsp.missed_ids.size());
|
||||
|
||||
|
||||
LOG_PRINT_L3("[NOTIFY]NOTIFY_RESPONSE_GET_OBJECTS: " << ENDL << currency::print_kv_structure(rsp));
|
||||
post_notify<NOTIFY_RESPONSE_GET_OBJECTS>(rsp, context);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -383,12 +393,17 @@ namespace currency
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(ret_v, msg) if (check_stop_flag_and_drop_cc(context)) { LOG_PRINT_YELLOW("Stop flag detected within NOTIFY_RESPONSE_GET_OBJECTS. " << msg, LOG_LEVEL_0); return ret_v; }
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
int t_currency_protocol_handler<t_core>::handle_response_get_objects(int command, NOTIFY_RESPONSE_GET_OBJECTS::request& arg, currency_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_L2("NOTIFY_RESPONSE_GET_OBJECTS");
|
||||
LOG_PRINT_L2("[HANDLE]NOTIFY_RESPONSE_GET_OBJECTS: arg.blocks.size()=" << arg.blocks.size() << ", arg.missed_ids.size()=" << arg.missed_ids.size() << ", arg.txs.size()=" << arg.txs.size());
|
||||
LOG_PRINT_L3("[HANDLE]NOTIFY_RESPONSE_GET_OBJECTS: " << ENDL << currency::print_kv_structure(arg));
|
||||
if(context.m_last_response_height > arg.current_blockchain_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_HAVE_OBJECTS: arg.m_current_blockchain_height=" << arg.current_blockchain_height
|
||||
|
|
@ -420,7 +435,7 @@ namespace currency
|
|||
total_blocks_parsing_time += block_parsing_time;
|
||||
|
||||
//to avoid concurrency in core between connections, suspend connections which delivered block later then first one
|
||||
if(count = 2)
|
||||
if(count == 2)
|
||||
{
|
||||
if(m_core.have_block(get_block_hash(b)))
|
||||
{
|
||||
|
|
@ -511,7 +526,8 @@ namespace currency
|
|||
}
|
||||
if(bvc.m_marked_as_orphaned)
|
||||
{
|
||||
LOG_PRINT_L0("Block received at sync phase was marked as orphaned, dropping connection");
|
||||
LOG_PRINT_L0("Block received at sync phase was marked as orphaned, dropping connection, details on response: " << ENDL << print_kv_structure(arg));
|
||||
|
||||
m_p2p->drop_connection(context);
|
||||
m_p2p->add_ip_fail(context.m_remote_ip);
|
||||
return 1;
|
||||
|
|
@ -565,13 +581,16 @@ namespace currency
|
|||
template<class t_core>
|
||||
int t_currency_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, currency_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_L2("[HANDLE]NOTIFY_REQUEST_CHAIN: block_ids.size()=" << arg.block_ids.size());
|
||||
LOG_PRINT_L3("[HANDLE]NOTIFY_REQUEST_CHAIN: " << print_kv_structure(arg));
|
||||
NOTIFY_RESPONSE_CHAIN_ENTRY::request r;
|
||||
if(!m_core.find_blockchain_supplement(arg.block_ids, r))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Failed to handle NOTIFY_REQUEST_CHAIN.");
|
||||
return 1;
|
||||
}
|
||||
LOG_PRINT_L2("[HANDLE]NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
|
||||
LOG_PRINT_L2("[NOTIFY]NOTIFY_RESPONSE_CHAIN_ENTRY: m_start_height=" << r.start_height << ", m_total_height=" << r.total_height << ", m_block_ids.size()=" << r.m_block_ids.size());
|
||||
LOG_PRINT_L3("[NOTIFY]NOTIFY_RESPONSE_CHAIN_ENTRY: " << print_kv_structure(r));
|
||||
post_notify<NOTIFY_RESPONSE_CHAIN_ENTRY>(r, context);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -599,14 +618,16 @@ namespace currency
|
|||
context.m_priv.m_needed_objects.erase(it++);
|
||||
}
|
||||
|
||||
LOG_PRINT_L2("[REQUESTING]NOTIFY_REQUEST_GET_OBJECTS: requested_cumulative_size=" << requested_cumulative_size << ", blocks.size()=" << req.blocks.size() << ", txs.size()=" << req.txs.size());
|
||||
LOG_PRINT_L2("[NOTIFY]NOTIFY_REQUEST_GET_OBJECTS(req_missing): requested_cumulative_size=" << requested_cumulative_size << ", blocks.size()=" << req.blocks.size() << ", txs.size()=" << req.txs.size());
|
||||
LOG_PRINT_L3("[NOTIFY]NOTIFY_REQUEST_GET_OBJECTS(req_missing): " << ENDL << currency::print_kv_structure(req));
|
||||
post_notify<NOTIFY_REQUEST_GET_OBJECTS>(req, context);
|
||||
}else if(context.m_last_response_height < context.m_remote_blockchain_height-1)
|
||||
{//we have to fetch more objects ids, request blockchain entry
|
||||
|
||||
NOTIFY_REQUEST_CHAIN::request r = boost::value_initialized<NOTIFY_REQUEST_CHAIN::request>();
|
||||
m_core.get_short_chain_history(r.block_ids);
|
||||
LOG_PRINT_L2("[REQUESTING]NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
LOG_PRINT_L2("[NOTIFY]NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() );
|
||||
LOG_PRINT_L3("[NOTIFY]NOTIFY_REQUEST_CHAIN: " << ENDL << print_kv_structure(r) );
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
}else
|
||||
{
|
||||
|
|
@ -620,7 +641,7 @@ namespace currency
|
|||
<< "\r\non connection [" << net_utils::print_connection_context_short(context)<< "]");
|
||||
|
||||
context.m_state = currency_connection_context::state_normal;
|
||||
LOG_PRINT_GREEN("[HANDLE]NOTIFY_REQUEST_GET_OBJECTS: SYNCHRONIZED OK", LOG_LEVEL_0);
|
||||
LOG_PRINT_GREEN("[REQUEST_MISSING_OBJECTS]: SYNCHRONIZED OK", LOG_LEVEL_0);
|
||||
on_connection_synchronized();
|
||||
}
|
||||
return true;
|
||||
|
|
@ -725,8 +746,9 @@ namespace currency
|
|||
template<class t_core>
|
||||
int t_currency_protocol_handler<t_core>::handle_response_chain_entry(int command, NOTIFY_RESPONSE_CHAIN_ENTRY::request& arg, currency_connection_context& context)
|
||||
{
|
||||
LOG_PRINT_L2("NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
|
||||
LOG_PRINT_L2("[HANDLE]NOTIFY_RESPONSE_CHAIN_ENTRY: m_block_ids.size()=" << arg.m_block_ids.size()
|
||||
<< ", m_start_height=" << arg.start_height << ", m_total_height=" << arg.total_height);
|
||||
LOG_PRINT_L3("[HANDLE]NOTIFY_RESPONSE_CHAIN_ENTRY: " << ENDL << currency::print_kv_structure(arg));
|
||||
|
||||
if(!arg.m_block_ids.size())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@
|
|||
"OPEN_WALLET": "Open existing wallet",
|
||||
"RESTORE_WALLET": "Restore from backup",
|
||||
"WALLET_DETAILS": "Wallet details",
|
||||
"ASSIGN_ALIAS": "Assign alias",
|
||||
"EDIT_ALIAS": "Edit alias",
|
||||
"TRANSFER_ALIAS": "Transfer alias",
|
||||
"CONTRACTS": "Contracts",
|
||||
"NEW_PURCHASE": "New purchase",
|
||||
"OLD_PURCHASE": "Purchase"
|
||||
|
|
@ -148,6 +151,68 @@
|
|||
"NAME_DUPLICATE": "Name is duplicate."
|
||||
}
|
||||
},
|
||||
"ASSIGN_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"PLACEHOLDER": "@ Enter alias",
|
||||
"TOOLTIP": "An alias is a shortened form or your account. An alias can only include Latin letters, numbers and characters “.” and “-”. It must start with “@”."
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment",
|
||||
"TOOLTIP": "The comment will be visible to anyone who wants to make a payment to your alias. You can provide details about your business, contacts, or include any text. Comments can be edited later."
|
||||
},
|
||||
"COST": "Cost to create alias {{value}} {{currency}}",
|
||||
"BUTTON_ASSIGN": "Assign",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required.",
|
||||
"NAME_WRONG": "Alias has wrong name.",
|
||||
"NAME_LENGTH": "The alias must be 6-25 characters long.",
|
||||
"NAME_EXISTS": "Alias name already exists."
|
||||
},
|
||||
"ONE_ALIAS": "You can create only one alias per wallet",
|
||||
"REQUEST_ADD_REG": "The alias will be assigned within 10 minutes"
|
||||
},
|
||||
"EDIT_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"NO_MONEY": "You do not have enough funds to change the comment to this alias"
|
||||
},
|
||||
"COST": "Cost to edit alias {{value}} {{currency}}",
|
||||
"BUTTON_EDIT": "Edit",
|
||||
"BUTTON_CANCEL": "Cancel"
|
||||
},
|
||||
"TRANSFER_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
},
|
||||
"ADDRESS": {
|
||||
"LABEL": "The account to which the alias will be transferred",
|
||||
"PLACEHOLDER": "Enter account number"
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"WRONG_ADDRESS": "No wallet with this account exists",
|
||||
"ALIAS_EXISTS": "This account already has an alias",
|
||||
"NO_MONEY": "You do not have enough funds to transfer this alias"
|
||||
},
|
||||
"COST": "Cost to transfer alias {{value}} {{currency}}",
|
||||
"BUTTON_TRANSFER": "Transfer",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"REQUEST_SEND_REG": "The alias will be transferred within 10 minutes"
|
||||
},
|
||||
"SEND": {
|
||||
"ADDRESS": "Address",
|
||||
"AMOUNT": "Amount",
|
||||
|
|
@ -190,6 +255,8 @@
|
|||
"UNDEFINED": "Undefined",
|
||||
"COMPLETE_BUYER": "Successfully complete contract, return remaining pledge",
|
||||
"COMPLETE_SELLER": "Successfully complete contract, receive payment on contract, and return pledge",
|
||||
"CREATE_ALIAS": "Fee for assigning alias",
|
||||
"UPDATE_ALIAS": "Fee for editing alias",
|
||||
"MINED": "Mined funds",
|
||||
"CREATE_CONTRACT": "Send contract offer",
|
||||
"PLEDGE_CONTRACT": "Make pledge on offer",
|
||||
|
|
@ -370,7 +437,14 @@
|
|||
"FILE_RESTORED": "The wallet file was corrupted. We have recovered the keys and the wallet from the blockchain",
|
||||
"FILE_NOT_FOUND": "File not found",
|
||||
"FILE_EXIST": "A file with that name already exists. Enter another name to save the file under",
|
||||
"FILE_NOT_SAVED": "You cannot save a wallet file in this folder. Please choose another folder."
|
||||
"FILE_NOT_SAVED": "You cannot save a wallet file in this folder. Please choose another folder.",
|
||||
"TX_TYPE_NORMAL": "Error. The payment from the wallet",
|
||||
"TX_TYPE_NORMAL_TO": "to",
|
||||
"TX_TYPE_NORMAL_END": "was not completed.",
|
||||
"TX_TYPE_NEW_ALIAS": "Error. Failed to register alias to safe",
|
||||
"TX_TYPE_NEW_ALIAS_END": "Please try again.",
|
||||
"TX_TYPE_UPDATE_ALIAS": "Error. Failed to change comment to alias in safe",
|
||||
"TX_TYPE_COIN_BASE": "Error. The payment was not completed."
|
||||
},
|
||||
"CONTEXT_MENU": {
|
||||
"COPY": "copy",
|
||||
|
|
|
|||
|
|
@ -141,8 +141,8 @@ button {
|
|||
width: 100%;
|
||||
min-width: 100%;
|
||||
height: 100%;
|
||||
min-height: 7rem;
|
||||
max-height: 7rem;
|
||||
min-height: 7.5rem;
|
||||
max-height: 7.5rem;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
|
||||
|
|
@ -157,6 +157,7 @@ button {
|
|||
font-size: 1rem;
|
||||
line-height: 1.4rem;
|
||||
align-self: flex-end;
|
||||
text-align: right;
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(redTextColor);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
app-main, app-create-wallet, app-open-wallet, app-restore-wallet, app-seed-phrase, app-wallet-details, app-settings, app-login {
|
||||
app-main, app-create-wallet, app-open-wallet, app-restore-wallet, app-seed-phrase, app-wallet-details, app-assign-alias, app-edit-alias, app-transfer-alias, app-settings, app-login {
|
||||
flex: 1 1 auto;
|
||||
padding: 3rem;
|
||||
min-width: 85rem;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,16 @@ app-wallet {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alias {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
|
|
|
|||
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 one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,10 +1,11 @@
|
|||
import {Directive, Input, ElementRef, HostListener, Renderer2, HostBinding} from '@angular/core';
|
||||
import {Directive, Input, ElementRef, HostListener, Renderer2, HostBinding, OnDestroy} from '@angular/core';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
|
||||
@Directive({
|
||||
selector: '[tooltip]'
|
||||
})
|
||||
|
||||
export class TooltipDirective {
|
||||
export class TooltipDirective implements OnDestroy {
|
||||
|
||||
@HostBinding('style.cursor') cursor = 'pointer';
|
||||
|
||||
|
|
@ -16,8 +17,9 @@ export class TooltipDirective {
|
|||
tooltip: HTMLElement;
|
||||
|
||||
removeTooltipTimeout;
|
||||
removeTooltipTimeoutInner;
|
||||
|
||||
constructor(private el: ElementRef, private renderer: Renderer2) {
|
||||
constructor(private el: ElementRef, private renderer: Renderer2, private route: ActivatedRoute) {
|
||||
}
|
||||
|
||||
@HostListener('mouseenter') onMouseEnter() {
|
||||
|
|
@ -40,9 +42,9 @@ export class TooltipDirective {
|
|||
}
|
||||
|
||||
hide() {
|
||||
this.removeTooltipTimeout = setTimeout( () => {
|
||||
this.removeTooltipTimeout = setTimeout(() => {
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '0');
|
||||
window.setTimeout(() => {
|
||||
this.removeTooltipTimeoutInner = setTimeout(() => {
|
||||
this.renderer.removeChild(document.body, this.tooltip);
|
||||
this.tooltip = null;
|
||||
}, this.delay);
|
||||
|
|
@ -51,6 +53,7 @@ export class TooltipDirective {
|
|||
|
||||
cancelHide() {
|
||||
clearTimeout(this.removeTooltipTimeout);
|
||||
clearTimeout(this.removeTooltipTimeoutInner);
|
||||
this.renderer.setStyle(this.tooltip, 'opacity', '1');
|
||||
}
|
||||
|
||||
|
|
@ -62,10 +65,23 @@ export class TooltipDirective {
|
|||
this.tooltip = this.tooltipInner;
|
||||
}
|
||||
this.renderer.appendChild(document.body, this.tooltip);
|
||||
|
||||
this.tooltip.addEventListener('mouseenter', () => {
|
||||
this.cancelHide();
|
||||
});
|
||||
this.tooltip.addEventListener('mouseleave', () => {
|
||||
if (this.tooltip) {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
|
||||
this.renderer.setStyle(document.body, 'position', 'relative');
|
||||
this.renderer.setStyle(this.tooltip, 'position', 'absolute');
|
||||
if (this.tooltipClass !== null) {
|
||||
this.renderer.addClass(this.tooltip, this.tooltipClass);
|
||||
const classes = this.tooltipClass.split(' ');
|
||||
for (let i = 0; i < classes.length; i++) {
|
||||
this.renderer.addClass(this.tooltip, classes[i]);
|
||||
}
|
||||
}
|
||||
if (this.placement !== null) {
|
||||
this.renderer.addClass(this.tooltip, 'ng-tooltip-' + this.placement);
|
||||
|
|
@ -114,4 +130,14 @@ export class TooltipDirective {
|
|||
this.renderer.setStyle(this.tooltip, 'left', hostPos.right + 'px');
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
clearTimeout(this.removeTooltipTimeout);
|
||||
clearTimeout(this.removeTooltipTimeoutInner);
|
||||
if (this.tooltip) {
|
||||
this.renderer.removeChild(document.body, this.tooltip);
|
||||
this.tooltip = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ export class Wallet {
|
|||
mined_total: number;
|
||||
tracking_hey: string;
|
||||
|
||||
alias?: string;
|
||||
alias?: object;
|
||||
wakeAlias?: boolean;
|
||||
staking?: boolean;
|
||||
new_messages?: number;
|
||||
new_contracts?: number;
|
||||
|
|
@ -45,7 +46,7 @@ export class Wallet {
|
|||
this.mined_total = mined;
|
||||
this.tracking_hey = tracking;
|
||||
|
||||
this.alias = '';
|
||||
this.alias = {};
|
||||
this.staking = false;
|
||||
this.new_messages = 0;
|
||||
this.new_contracts = 0;
|
||||
|
|
@ -127,6 +128,15 @@ export class Wallet {
|
|||
}
|
||||
}
|
||||
|
||||
removeFromHistory(hash: string): void {
|
||||
for (let i = 0; i < this.history.length; i++) {
|
||||
if (this.history[i].tx_hash === hash) {
|
||||
this.history.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prepareContractsAfterOpen(items: any[], exp_med_ts, height_app, viewedContracts, notViewedContracts): void {
|
||||
const wallet = this;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ export class HistoryTypeMessagesPipe implements PipeTransform {
|
|||
// return '';
|
||||
// case 3:
|
||||
// return '';
|
||||
// case 4:
|
||||
// return '';
|
||||
// case 5:
|
||||
// return '';
|
||||
case 4:
|
||||
return this.translate.instant('HISTORY.TYPE_MESSAGES.CREATE_ALIAS');
|
||||
case 5:
|
||||
return this.translate.instant('HISTORY.TYPE_MESSAGES.UPDATE_ALIAS');
|
||||
case 6:
|
||||
return this.translate.instant('HISTORY.TYPE_MESSAGES.MINED');
|
||||
case 7:
|
||||
|
|
|
|||
|
|
@ -112,6 +112,14 @@ export class BackendService {
|
|||
}
|
||||
}
|
||||
break;
|
||||
case 'NOT_FOUND': if (command !== 'open_wallet' && command !== 'get_alias_info_by_name' && command !== 'get_alias_info_by_address') {
|
||||
error_translate = this.translate.instant('ERRORS.FILE_NOT_FOUND');
|
||||
params = JSON.parse(params);
|
||||
if (params.path) {
|
||||
error_translate += ': ' + params.path;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'CANCELED':
|
||||
case '':
|
||||
break;
|
||||
|
|
@ -135,7 +143,7 @@ export class BackendService {
|
|||
}
|
||||
|
||||
private bigNumberParser(key, val) {
|
||||
if (val.constructor.name === 'BigNumber' && ['balance', 'unlocked_balance', 'amount', 'fee', 'b_fee', 'to_pay', 'a_pledge', 'b_pledge'].indexOf(key) === -1) {
|
||||
if (val.constructor.name === 'BigNumber' && ['balance', 'unlocked_balance', 'amount', 'fee', 'b_fee', 'to_pay', 'a_pledge', 'b_pledge', 'coast'].indexOf(key) === -1) {
|
||||
return val.toNumber();
|
||||
}
|
||||
if (key === 'rcv' || key === 'spn') {
|
||||
|
|
@ -363,7 +371,6 @@ export class BackendService {
|
|||
this.runCommand('restore_wallet', params, callback);
|
||||
}
|
||||
|
||||
|
||||
sendMoney(from_wallet_id, to_address, amount, fee, mixin, comment, callback) {
|
||||
const params = {
|
||||
wallet_id: parseInt(from_wallet_id, 10),
|
||||
|
|
@ -503,6 +510,82 @@ export class BackendService {
|
|||
this.runCommand('set_localization_strings', params, callback);
|
||||
}
|
||||
|
||||
registerAlias (wallet_id, alias, address, fee, comment, reward, callback) {
|
||||
const params = {
|
||||
wallet_id: wallet_id,
|
||||
alias: {
|
||||
alias: alias,
|
||||
address: address,
|
||||
tracking_key: '',
|
||||
comment: comment
|
||||
},
|
||||
fee: this.moneyToIntPipe.transform(fee),
|
||||
reward: this.moneyToIntPipe.transform(reward)
|
||||
};
|
||||
this.runCommand('request_alias_registration', params, callback);
|
||||
}
|
||||
|
||||
updateAlias (wallet_id, alias, fee, callback) {
|
||||
const params = {
|
||||
wallet_id: wallet_id,
|
||||
alias: {
|
||||
alias: alias.name.replace('@', ''),
|
||||
address: alias.address,
|
||||
tracking_key: '',
|
||||
comment: alias.comment
|
||||
},
|
||||
fee: this.moneyToIntPipe.transform(fee)
|
||||
};
|
||||
this.runCommand('request_alias_update', params, callback);
|
||||
}
|
||||
|
||||
getAllAliases (callback) {
|
||||
this.runCommand('get_all_aliases', {}, callback);
|
||||
}
|
||||
|
||||
getAliasByName (value, callback) {
|
||||
return this.runCommand('get_alias_info_by_name', value, callback);
|
||||
}
|
||||
|
||||
getAliasByAddress (value, callback) {
|
||||
return this.runCommand('get_alias_info_by_address', value, callback);
|
||||
}
|
||||
|
||||
getAliasCoast (alias, callback) {
|
||||
this.runCommand('get_alias_coast', {v: alias}, callback);
|
||||
}
|
||||
|
||||
getWalletAlias(address) {
|
||||
if (address != null && this.variablesService.daemon_state === 2) {
|
||||
if (this.variablesService.aliasesChecked[address] == null) {
|
||||
this.variablesService.aliasesChecked[address] = {};
|
||||
if (this.variablesService.aliases.length) {
|
||||
for (let i = 0, length = this.variablesService.aliases.length; i < length; i++) {
|
||||
if (i in this.variablesService.aliases && this.variablesService.aliases[i]['address'] === address) {
|
||||
this.variablesService.aliasesChecked[address]['name'] = this.variablesService.aliases[i].name;
|
||||
this.variablesService.aliasesChecked[address]['address'] = this.variablesService.aliases[i].address;
|
||||
this.variablesService.aliasesChecked[address]['comment'] = this.variablesService.aliases[i].comment;
|
||||
return this.variablesService.aliasesChecked[address];
|
||||
}
|
||||
}
|
||||
}
|
||||
this.getAliasByAddress(address, (status, data) => {
|
||||
if (status) {
|
||||
this.variablesService.aliasesChecked[data.address]['name'] = '@' + data.alias;
|
||||
this.variablesService.aliasesChecked[data.address]['address'] = data.address;
|
||||
this.variablesService.aliasesChecked[data.address]['comment'] = data.comment;
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.variablesService.aliasesChecked[address];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
getPoolInfo(callback) {
|
||||
this.runCommand('get_tx_pool_info', {}, callback);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -520,8 +603,6 @@ export class BackendService {
|
|||
return this.runCommand('is_file_exist', path, callback);
|
||||
},
|
||||
|
||||
|
||||
|
||||
isAutoStartEnabled: function (callback) {
|
||||
this.runCommand('is_autostart_enabled', {}, function (status, data) {
|
||||
if (angular.isFunction(callback)) {
|
||||
|
|
@ -530,8 +611,6 @@ export class BackendService {
|
|||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
setLogLevel: function (level) {
|
||||
return this.runCommand('set_log_level', asVal(level))
|
||||
},
|
||||
|
|
@ -558,66 +637,16 @@ export class BackendService {
|
|||
})
|
||||
},
|
||||
|
||||
|
||||
resync_wallet: function (wallet_id, callback) {
|
||||
this.runCommand('resync_wallet', {wallet_id: wallet_id}, callback);
|
||||
},
|
||||
|
||||
registerAlias: function (wallet_id, alias, address, fee, comment, reward, callback) {
|
||||
var params = {
|
||||
"wallet_id": wallet_id,
|
||||
"alias": {
|
||||
"alias": alias,
|
||||
"address": address,
|
||||
"tracking_key": "",
|
||||
"comment": comment
|
||||
},
|
||||
"fee": $filter('money_to_int')(fee),
|
||||
"reward": $filter('money_to_int')(reward)
|
||||
};
|
||||
this.runCommand('request_alias_registration', params, callback);
|
||||
},
|
||||
|
||||
updateAlias: function (wallet_id, alias, fee, callback) {
|
||||
var params = {
|
||||
wallet_id: wallet_id,
|
||||
alias: {
|
||||
"alias": alias.name.replace("@", ""),
|
||||
"address": alias.address,
|
||||
"tracking_key": "",
|
||||
"comment": alias.comment
|
||||
},
|
||||
fee: $filter('money_to_int')(fee)
|
||||
};
|
||||
this.runCommand('request_alias_update', params, callback);
|
||||
},
|
||||
|
||||
getAllAliases: function (callback) {
|
||||
this.runCommand('get_all_aliases', {}, callback);
|
||||
},
|
||||
|
||||
getAliasByName: function (value, callback) {
|
||||
return this.runCommand('get_alias_info_by_name', value, callback);
|
||||
},
|
||||
|
||||
getAliasByAddress: function (value, callback) {
|
||||
return this.runCommand('get_alias_info_by_address', value, callback);
|
||||
},
|
||||
|
||||
getPoolInfo: function (callback) {
|
||||
this.runCommand('get_tx_pool_info', {}, callback);
|
||||
},
|
||||
|
||||
storeFile: function (path, buff, callback) {
|
||||
this.backendObject['store_to_file'](path, (typeof buff === 'string' ? buff : JSON.stringify(buff)), function (data) {
|
||||
backendCallback(data, {}, callback, 'store_to_file');
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
getMiningEstimate: function (amount_coins, time, callback) {
|
||||
var params = {
|
||||
"amount_coins": $filter('money_to_int')(amount_coins),
|
||||
|
|
@ -634,29 +663,15 @@ export class BackendService {
|
|||
this.runCommand('backup_wallet_keys', params, callback);
|
||||
},
|
||||
|
||||
|
||||
getAliasCoast: function (alias, callback) {
|
||||
this.runCommand('get_alias_coast', asVal(alias), callback);
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
setBlockedIcon: function (enabled, callback) {
|
||||
var mode = (enabled) ? "blocked" : "normal";
|
||||
Service.runCommand('bool_toggle_icon', mode, callback);
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
getWalletInfo: function (wallet_id, callback) {
|
||||
this.runCommand('get_wallet_info', {wallet_id: wallet_id}, callback);
|
||||
},
|
||||
|
||||
|
||||
|
||||
printText: function (content) {
|
||||
return this.runCommand('print_text', {html_text: content});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export class ModalService {
|
|||
);
|
||||
|
||||
this.components[length - 1].instance['type'] = type;
|
||||
this.components[length - 1].instance['message'] = this.translate.instant(message);
|
||||
this.components[length - 1].instance['message'] = message.length ? this.translate.instant(message) : '';
|
||||
this.components[length - 1].instance['close'].subscribe(() => {
|
||||
this.removeModal(length - 1);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,9 +38,14 @@ export class VariablesService {
|
|||
|
||||
public wallets: Array<Wallet> = [];
|
||||
public currentWallet: Wallet;
|
||||
public aliases: any = [];
|
||||
public aliasesChecked: any = {};
|
||||
public aliasesUnconfirmed: any = [];
|
||||
public enableAliasSearch = false;
|
||||
|
||||
getHeightAppEvent = new BehaviorSubject(null);
|
||||
getRefreshStackingEvent = new BehaviorSubject(null);
|
||||
getAliasChangedEvent = new BehaviorSubject(null);
|
||||
|
||||
public idle = new Idle()
|
||||
.whenNotInteractive()
|
||||
|
|
@ -70,6 +75,10 @@ export class VariablesService {
|
|||
this.getHeightAppEvent.next(wallet_id);
|
||||
}
|
||||
|
||||
changeAliases() {
|
||||
this.getAliasChangedEvent.next(true);
|
||||
}
|
||||
|
||||
setCurrentWallet(id): void {
|
||||
this.wallets.forEach((wallet) => {
|
||||
if (wallet.wallet_id === id) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ import { OpenWalletComponent } from './open-wallet/open-wallet.component';
|
|||
import { RestoreWalletComponent } from './restore-wallet/restore-wallet.component';
|
||||
import { SeedPhraseComponent } from './seed-phrase/seed-phrase.component';
|
||||
import { WalletDetailsComponent } from './wallet-details/wallet-details.component';
|
||||
import { AssignAliasComponent } from './assign-alias/assign-alias.component';
|
||||
import { EditAliasComponent } from "./edit-alias/edit-alias.component";
|
||||
import { TransferAliasComponent } from "./transfer-alias/transfer-alias.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
|
|
@ -100,6 +103,18 @@ const routes: Routes = [
|
|||
path: 'details',
|
||||
component: WalletDetailsComponent
|
||||
},
|
||||
{
|
||||
path: 'assign-alias',
|
||||
component: AssignAliasComponent
|
||||
},
|
||||
{
|
||||
path: 'edit-alias',
|
||||
component: EditAliasComponent
|
||||
},
|
||||
{
|
||||
path: 'transfer-alias',
|
||||
component: TransferAliasComponent
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
component: SettingsComponent
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {VariablesService} from './_helpers/services/variables.service';
|
|||
import {ContextMenuComponent} from 'ngx-contextmenu';
|
||||
import {IntToMoneyPipe} from './_helpers/pipes/int-to-money.pipe';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import {ModalService} from './_helpers/services/modal.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
|
|
@ -30,7 +31,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
private router: Router,
|
||||
private variablesService: VariablesService,
|
||||
private ngZone: NgZone,
|
||||
private intToMoneyPipe: IntToMoneyPipe
|
||||
private intToMoneyPipe: IntToMoneyPipe,
|
||||
private modalService: ModalService
|
||||
) {
|
||||
translate.addLangs(['en', 'fr']);
|
||||
translate.setDefaultLang('en');
|
||||
|
|
@ -64,7 +66,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.backend.webkitLaunchedScript();
|
||||
|
||||
|
||||
this.backend.is_remnotenode_mode_preconfigured((status, data) => {
|
||||
// if (data === 'FALSE') {
|
||||
// } else {
|
||||
|
|
@ -99,7 +100,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
this.onQuitRequest = true;
|
||||
});
|
||||
|
||||
|
||||
this.backend.eventSubscribe('update_wallet_status', (data) => {
|
||||
console.log('----------------- update_wallet_status -----------------');
|
||||
console.log(data);
|
||||
|
|
@ -126,7 +126,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
this.backend.eventSubscribe('wallet_sync_progress', (data) => {
|
||||
console.log('----------------- wallet_sync_progress -----------------');
|
||||
console.log(data);
|
||||
|
|
@ -144,7 +143,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
this.backend.eventSubscribe('update_daemon_state', (data) => {
|
||||
console.log('----------------- update_daemon_state -----------------');
|
||||
console.log('DAEMON:' + data.daemon_network_state);
|
||||
|
|
@ -154,10 +152,10 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
this.variablesService.setHeightApp(data.height);
|
||||
|
||||
this.ngZone.run(() => {
|
||||
this.variablesService.daemon_state = data.daemon_network_state;
|
||||
if (data.daemon_network_state === 1) {
|
||||
const max = data.max_net_seen_height - data.synchronization_start_height;
|
||||
const current = data.height - data.synchronization_start_height;
|
||||
this.variablesService.daemon_state = data['daemon_network_state'];
|
||||
if (data['daemon_network_state'] === 1) {
|
||||
const max = data['max_net_seen_height'] - data['synchronization_start_height'];
|
||||
const current = data.height - data['synchronization_start_height'];
|
||||
const return_val = Math.floor((current * 100 / max) * 100) / 100;
|
||||
if (max === 0 || return_val < 0) {
|
||||
this.variablesService.sync.progress_value = 0;
|
||||
|
|
@ -171,7 +169,8 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
}
|
||||
});
|
||||
if (!this.firstOnlineState) {
|
||||
if (!this.firstOnlineState && data['daemon_network_state'] === 2) {
|
||||
this.getAliases();
|
||||
this.backend.getDefaultFee((status_fee, data_fee) => {
|
||||
this.variablesService.default_fee_big = new BigNumber(data_fee);
|
||||
this.variablesService.default_fee = this.intToMoneyPipe.transform(data_fee);
|
||||
|
|
@ -188,6 +187,19 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.variablesService.aliasesUnconfirmed.length) {
|
||||
let alias = false;
|
||||
for (let i = 0; i < this.variablesService.aliasesUnconfirmed.length; i++) {
|
||||
if (this.variablesService.aliasesUnconfirmed[i].tx_hash === data.ti.tx_hash) {
|
||||
alias = this.variablesService.aliasesUnconfirmed[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (alias) {
|
||||
this.variablesService.aliasesUnconfirmed.splice(this.variablesService.aliasesUnconfirmed.indexOf(alias), 1);
|
||||
}
|
||||
}
|
||||
|
||||
const wallet_id = data.wallet_id;
|
||||
const tr_info = data.ti;
|
||||
|
||||
|
|
@ -315,72 +327,138 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
this.backend.eventSubscribe('money_transfer_cancel', (data) => {
|
||||
console.log('----------------- money_transfer_cancel -----------------');
|
||||
console.log(data);
|
||||
|
||||
// if (!data.ti) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// var wallet_id = data.wallet_id;
|
||||
// var tr_info = data.ti;
|
||||
// var wallet = $rootScope.getWalletById(wallet_id);
|
||||
// if (wallet) {
|
||||
// if ( tr_info.hasOwnProperty("contract") ){
|
||||
// for (var i = 0; i < $rootScope.contracts.length; i++) {
|
||||
// if ($rootScope.contracts[i].contract_id === tr_info.contract[0].contract_id && $rootScope.contracts[i].is_a === tr_info.contract[0].is_a) {
|
||||
// if ($rootScope.contracts[i].state === 1 || $rootScope.contracts[i].state === 110) {
|
||||
// $rootScope.contracts[i].isNew = true;
|
||||
// $rootScope.contracts[i].state = 140;
|
||||
// $rootScope.getContractsRecount(); //escrow_code
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// angular.forEach(wallet.history, function (tr_item, key) {
|
||||
// if (tr_item.tx_hash === tr_info.tx_hash) {
|
||||
// wallet.history.splice(key, 1);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// var error_tr = '';
|
||||
// switch (tr_info.tx_type) {
|
||||
// case 0:
|
||||
// error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL') + '<br>' +
|
||||
// tr_info.tx_hash + '<br>' + wallet.name + '<br>' + wallet.address + '<br>' +
|
||||
// $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL_TO') + ' ' + $rootScope.moneyParse(tr_info.amount) + ' ' +
|
||||
// $filter('translate')('ERROR_GUI_TX_TYPE_NORMAL_END');
|
||||
// informer.error(error_tr);
|
||||
// break;
|
||||
// case 1:
|
||||
// informer.error('ERROR_GUI_TX_TYPE_PUSH_OFFER');
|
||||
// break;
|
||||
// case 2:
|
||||
// informer.error('ERROR_GUI_TX_TYPE_UPDATE_OFFER');
|
||||
// break;
|
||||
// case 3:
|
||||
// informer.error('ERROR_GUI_TX_TYPE_CANCEL_OFFER');
|
||||
// break;
|
||||
// case 4:
|
||||
// error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS') + '<br>' +
|
||||
// tr_info.tx_hash + '<br>' + wallet.name + '<br>' + wallet.address + '<br>' +
|
||||
// $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS_END');
|
||||
// informer.error(error_tr);
|
||||
// break;
|
||||
// case 5:
|
||||
// error_tr = $filter('translate')('ERROR_GUI_TX_TYPE_UPDATE_ALIAS') + '<br>' +
|
||||
// tr_info.tx_hash + '<br>' + wallet.name + '<br>' + wallet.address + '<br>' +
|
||||
// $filter('translate')('ERROR_GUI_TX_TYPE_NEW_ALIAS_END');
|
||||
// informer.error(error_tr);
|
||||
// break;
|
||||
// case 6:
|
||||
// informer.error('ERROR_GUI_TX_TYPE_COIN_BASE');
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
if (!data.ti) {
|
||||
return;
|
||||
}
|
||||
|
||||
const wallet_id = data.wallet_id;
|
||||
const tr_info = data.ti;
|
||||
const wallet = this.variablesService.getWallet(wallet_id);
|
||||
|
||||
if (wallet) {
|
||||
if (tr_info.hasOwnProperty('contract')) {
|
||||
for (let i = 0; i < wallet.contracts.length; i++) {
|
||||
if (wallet.contracts[i].contract_id === tr_info.contract[0].contract_id && wallet.contracts[i].is_a === tr_info.contract[0].is_a) {
|
||||
if (wallet.contracts[i].state === 1 || wallet.contracts[i].state === 110) {
|
||||
wallet.contracts[i].is_new = true;
|
||||
wallet.contracts[i].state = 140;
|
||||
wallet.recountNewContracts();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wallet.removeFromHistory(tr_info.tx_hash);
|
||||
|
||||
let error_tr = '';
|
||||
switch (tr_info.tx_type) {
|
||||
case 0:
|
||||
error_tr = this.translate.instant('ERRORS.TX_TYPE_NORMAL') + '<br>' +
|
||||
tr_info.tx_hash + '<br>' + wallet.name + '<br>' + wallet.address + '<br>' +
|
||||
this.translate.instant('ERRORS.TX_TYPE_NORMAL_TO') + ' ' + this.intToMoneyPipe.transform(tr_info.amount) + ' ' +
|
||||
this.translate.instant('ERRORS.TX_TYPE_NORMAL_END');
|
||||
break;
|
||||
case 1:
|
||||
// this.translate.instant('ERRORS.TX_TYPE_PUSH_OFFER');
|
||||
break;
|
||||
case 2:
|
||||
// this.translate.instant('ERRORS.TX_TYPE_UPDATE_OFFER');
|
||||
break;
|
||||
case 3:
|
||||
// this.translate.instant('ERRORS.TX_TYPE_CANCEL_OFFER');
|
||||
break;
|
||||
case 4:
|
||||
error_tr = this.translate.instant('ERRORS.TX_TYPE_NEW_ALIAS') + '<br>' +
|
||||
tr_info.tx_hash + '<br>' + wallet.name + '<br>' + wallet.address + '<br>' +
|
||||
this.translate.instant('ERRORS.TX_TYPE_NEW_ALIAS_END');
|
||||
break;
|
||||
case 5:
|
||||
error_tr = this.translate.instant('ERRORS.TX_TYPE_UPDATE_ALIAS') + '<br>' +
|
||||
tr_info.tx_hash + '<br>' + wallet.name + '<br>' + wallet.address + '<br>' +
|
||||
this.translate.instant('ERRORS.TX_TYPE_NEW_ALIAS_END');
|
||||
break;
|
||||
case 6:
|
||||
error_tr = this.translate.instant('ERRORS.TX_TYPE_COIN_BASE');
|
||||
break;
|
||||
}
|
||||
if (error_tr) {
|
||||
this.modalService.prepareModal('error', error_tr);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.backend.eventSubscribe('on_core_event', (data) => {
|
||||
console.log('----------------- on_core_event -----------------');
|
||||
console.log(data);
|
||||
|
||||
data = JSON.parse(data);
|
||||
|
||||
if (data.events != null) {
|
||||
for (let i = 0, length = data.events.length; i < length; i++) {
|
||||
|
||||
switch (data.events[i].method) {
|
||||
case 'CORE_EVENT_BLOCK_ADDED': break;
|
||||
case 'CORE_EVENT_ADD_ALIAS':
|
||||
if (this.variablesService.aliasesChecked[data.events[i].details.address] != null) {
|
||||
this.variablesService.aliasesChecked[data.events[i].details.address]['name'] = '@' + data.events[i].details.alias;
|
||||
this.variablesService.aliasesChecked[data.events[i].details.address]['address'] = data.events[i].details.address;
|
||||
this.variablesService.aliasesChecked[data.events[i].details.address]['comment'] = data.events[i].details.comment;
|
||||
}
|
||||
if (this.variablesService.enableAliasSearch) {
|
||||
const newAlias = {
|
||||
name: '@' + data.events[i].details.alias,
|
||||
address: data.events[i].details.address,
|
||||
comment: data.events[i].details.comment
|
||||
};
|
||||
this.variablesService.aliases = this.variablesService.aliases.concat(newAlias);
|
||||
// this.variablesService.aliases = this.variablesService.aliases.sort((a, b) => {
|
||||
// if (a.name.length > b.name.length) return 1;
|
||||
// if (a.name.length < b.name.length) return -1;
|
||||
// if (a.name > b.name) return 1;
|
||||
// if (a.name < b.name) return -1;
|
||||
// return 0;
|
||||
// });
|
||||
this.variablesService.changeAliases();
|
||||
}
|
||||
break;
|
||||
case 'CORE_EVENT_UPDATE_ALIAS':
|
||||
for (const address in this.variablesService.aliasesChecked) {
|
||||
if (this.variablesService.aliasesChecked.hasOwnProperty(address)) {
|
||||
if (this.variablesService.aliasesChecked[address].name === '@' + data.events[i].details.alias) {
|
||||
if (this.variablesService.aliasesChecked[address].address !== data.events[i].details.details.address) {
|
||||
delete this.variablesService.aliasesChecked[address]['name'];
|
||||
delete this.variablesService.aliasesChecked[address]['address'];
|
||||
delete this.variablesService.aliasesChecked[address]['comment'];
|
||||
} else {
|
||||
this.variablesService.aliasesChecked[address].comment = data.events[i].details.details.comment;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.variablesService.aliasesChecked[data.events[i].details.details.address] != null) {
|
||||
this.variablesService.aliasesChecked[data.events[i].details.details.address]['name'] = '@' + data.events[i].details.alias;
|
||||
this.variablesService.aliasesChecked[data.events[i].details.details.address]['address'] = data.events[i].details.details.address;
|
||||
this.variablesService.aliasesChecked[data.events[i].details.details.address]['comment'] = data.events[i].details.details.comment;
|
||||
}
|
||||
if (this.variablesService.enableAliasSearch) {
|
||||
const CurrentAlias = this.variablesService.aliases.find((element) => element.name === '@' + data.events[i].details.alias);
|
||||
if (CurrentAlias) {
|
||||
CurrentAlias.address = data.events[i].details.details.address;
|
||||
CurrentAlias.comment = data.events[i].details.details.comment;
|
||||
}
|
||||
}
|
||||
this.variablesService.changeAliases();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.intervalUpdateContractsState = setInterval(() => {
|
||||
|
|
@ -454,6 +532,42 @@ export class AppComponent implements OnInit, OnDestroy {
|
|||
);
|
||||
}
|
||||
|
||||
getAliases() {
|
||||
this.backend.getAllAliases((status, data, error) => {
|
||||
if (error === 'CORE_BUSY') {
|
||||
window.setTimeout(() => {
|
||||
this.getAliases();
|
||||
}, 10000);
|
||||
} else if (error === 'OVERFLOW') {
|
||||
this.variablesService.aliases = [];
|
||||
this.variablesService.enableAliasSearch = false;
|
||||
} else {
|
||||
this.variablesService.enableAliasSearch = true;
|
||||
if (data.aliases && data.aliases.length) {
|
||||
this.variablesService.aliases = [];
|
||||
data.aliases.forEach(alias => {
|
||||
const newAlias = {
|
||||
name: '@' + alias.alias,
|
||||
address: alias.address,
|
||||
comment: alias.comment
|
||||
};
|
||||
this.variablesService.aliases.push(newAlias);
|
||||
});
|
||||
this.variablesService.wallets.forEach(wallet => {
|
||||
wallet.alias = this.backend.getWalletAlias(wallet.address);
|
||||
});
|
||||
this.variablesService.aliases = this.variablesService.aliases.sort((a, b) => {
|
||||
if (a.name.length > b.name.length) return 1;
|
||||
if (a.name.length < b.name.length) return -1;
|
||||
if (a.name > b.name) return 1;
|
||||
if (a.name < b.name) return -1;
|
||||
return 0;
|
||||
});
|
||||
this.variablesService.changeAliases();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
contextMenuCopy(target) {
|
||||
if (target && (target['nodeName'].toUpperCase() === 'TEXTAREA' || target['nodeName'].toUpperCase() === 'INPUT')) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ import { OpenWalletComponent } from './open-wallet/open-wallet.component';
|
|||
import { RestoreWalletComponent } from './restore-wallet/restore-wallet.component';
|
||||
import { SeedPhraseComponent } from './seed-phrase/seed-phrase.component';
|
||||
import { WalletDetailsComponent } from './wallet-details/wallet-details.component';
|
||||
import { AssignAliasComponent } from './assign-alias/assign-alias.component';
|
||||
import { EditAliasComponent } from './edit-alias/edit-alias.component';
|
||||
import { TransferAliasComponent } from './transfer-alias/transfer-alias.component';
|
||||
import { WalletComponent } from './wallet/wallet.component';
|
||||
import { SendComponent } from './send/send.component';
|
||||
import { ReceiveComponent } from './receive/receive.component';
|
||||
|
|
@ -20,23 +23,26 @@ import { HistoryComponent } from './history/history.component';
|
|||
import { ContractsComponent } from './contracts/contracts.component';
|
||||
import { PurchaseComponent } from './purchase/purchase.component';
|
||||
import { MessagesComponent } from './messages/messages.component';
|
||||
import { TypingMessageComponent } from './typing-message/typing-message.component';
|
||||
import { StakingComponent } from './staking/staking.component';
|
||||
|
||||
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
||||
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TypingMessageComponent } from './typing-message/typing-message.component';
|
||||
|
||||
import { BackendService } from './_helpers/services/backend.service';
|
||||
import { ModalService } from './_helpers/services/modal.service';
|
||||
import { MoneyToIntPipe } from './_helpers/pipes/money-to-int.pipe';
|
||||
import { IntToMoneyPipe } from './_helpers/pipes/int-to-money.pipe';
|
||||
import { StakingSwitchComponent } from './_helpers/directives/staking-switch/staking-switch.component';
|
||||
import { TooltipDirective } from './_helpers/directives/tooltip.directive';
|
||||
import { HistoryTypeMessagesPipe } from './_helpers/pipes/history-type-messages.pipe';
|
||||
import { ContractStatusMessagesPipe } from './_helpers/pipes/contract-status-messages.pipe';
|
||||
import { ContractTimeLeftPipe } from './_helpers/pipes/contract-time-left.pipe';
|
||||
import { TooltipDirective } from './_helpers/directives/tooltip.directive';
|
||||
import { InputValidateDirective } from './_helpers/directives/input-validate/input-validate.directive';
|
||||
import { StakingSwitchComponent } from './_helpers/directives/staking-switch/staking-switch.component';
|
||||
import { ModalContainerComponent } from './_helpers/directives/modal-container/modal-container.component';
|
||||
import { TransactionDetailsComponent } from './_helpers/directives/transaction-details/transaction-details.component';
|
||||
import { ContextMenuModule } from 'ngx-contextmenu';
|
||||
|
||||
export function HttpLoaderFactory(httpClient: HttpClient) {
|
||||
|
|
@ -45,9 +51,6 @@ export function HttpLoaderFactory(httpClient: HttpClient) {
|
|||
|
||||
|
||||
import { ChartModule, HIGHCHARTS_MODULES, Highcharts} from 'angular-highcharts';
|
||||
import { InputValidateDirective } from './_helpers/directives/input-validate/input-validate.directive';
|
||||
import { ModalContainerComponent } from './_helpers/directives/modal-container/modal-container.component';
|
||||
import { TransactionDetailsComponent } from './_helpers/directives/transaction-details/transaction-details.component';
|
||||
// import * as more from 'highcharts/highcharts-more.src';
|
||||
// import * as exporting from 'highcharts/modules/exporting.src';
|
||||
// import * as highstock from 'highcharts/modules/stock.src';
|
||||
|
|
@ -70,6 +73,9 @@ Highcharts.setOptions({
|
|||
RestoreWalletComponent,
|
||||
SeedPhraseComponent,
|
||||
WalletDetailsComponent,
|
||||
AssignAliasComponent,
|
||||
EditAliasComponent,
|
||||
TransferAliasComponent,
|
||||
WalletComponent,
|
||||
SendComponent,
|
||||
ReceiveComponent,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<div class="content">
|
||||
|
||||
<div class="head">
|
||||
<div class="breadcrumbs">
|
||||
<span [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">{{ wallet.name }}</span>
|
||||
<span>{{ 'BREADCRUMBS.ASSIGN_ALIAS' | translate }}</span>
|
||||
</div>
|
||||
<button class="back-btn" (click)="back()">
|
||||
<i class="icon back"></i>
|
||||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form class="form-assign" [formGroup]="assignForm">
|
||||
|
||||
<div class="input-block alias-name">
|
||||
<label for="alias-name" tooltip="{{ 'ASSIGN_ALIAS.NAME.TOOLTIP' | translate }}" placement="bottom" tooltipClass="table-tooltip assign-alias-tooltip" [delay]="500">
|
||||
{{ 'ASSIGN_ALIAS.NAME.LABEL' | translate }}
|
||||
</label>
|
||||
<input type="text" id="alias-name" formControlName="name" placeholder="{{ 'ASSIGN_ALIAS.NAME.PLACEHOLDER' | translate }}">
|
||||
<div class="error-block" *ngIf="assignForm.controls['name'].invalid && (assignForm.controls['name'].dirty || assignForm.controls['name'].touched)">
|
||||
<div *ngIf="assignForm.controls['name'].errors['required']">
|
||||
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_REQUIRED' | translate }}
|
||||
</div>
|
||||
<div *ngIf="assignForm.controls['name'].errors['pattern'] && assignForm.get('name').value.length > 6 && assignForm.get('name').value.length <= 25">
|
||||
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_WRONG' | translate }}
|
||||
</div>
|
||||
<div *ngIf="assignForm.get('name').value.length <= 6 || assignForm.get('name').value.length > 25">
|
||||
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_LENGTH' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="error-block" *ngIf="alias.exists">
|
||||
<div>
|
||||
{{ 'ASSIGN_ALIAS.FORM_ERRORS.NAME_EXISTS' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="input-block textarea">
|
||||
<label for="alias-comment" tooltip="{{ 'ASSIGN_ALIAS.COMMENT.TOOLTIP' | translate }}" placement="bottom" tooltipClass="table-tooltip assign-alias-tooltip" [delay]="500">
|
||||
{{ 'ASSIGN_ALIAS.COMMENT.LABEL' | translate }}
|
||||
</label>
|
||||
<textarea id="alias-comment" formControlName="comment" placeholder="{{ 'ASSIGN_ALIAS.COMMENT.PLACEHOLDER' | translate }}"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="alias-cost">{{ "ASSIGN_ALIAS.COST" | translate : {value: alias.price | intToMoney, currency: variablesService.defaultCurrency} }}</div>
|
||||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="blue-button" (click)="assignAlias()" [disabled]="!assignForm.valid || !canRegister || notEnoughMoney">{{ 'ASSIGN_ALIAS.BUTTON_ASSIGN' | translate }}</button>
|
||||
<button type="button" class="blue-button" (click)="back()">{{ 'ASSIGN_ALIAS.BUTTON_CANCEL' | translate }}</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
.form-assign {
|
||||
margin: 2.4rem 0;
|
||||
|
||||
.alias-name {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.alias-cost {
|
||||
font-size: 1.3rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.wrap-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 2.5rem -0.7rem;
|
||||
|
||||
button {
|
||||
margin: 0 0.7rem;
|
||||
width: 15rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.assign-alias-tooltip {
|
||||
font-size: 1.3rem;
|
||||
line-height: 2rem;
|
||||
padding: 1rem 1.5rem;
|
||||
max-width: 46rem;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AssignAliasComponent } from './assign-alias.component';
|
||||
|
||||
describe('AssignAliasComponent', () => {
|
||||
let component: AssignAliasComponent;
|
||||
let fixture: ComponentFixture<AssignAliasComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AssignAliasComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AssignAliasComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
import {Component, NgZone, OnInit, OnDestroy} from '@angular/core';
|
||||
import {FormGroup, FormControl, Validators} from '@angular/forms';
|
||||
import {Location} from '@angular/common';
|
||||
import {Router} from '@angular/router';
|
||||
import {BackendService} from '../_helpers/services/backend.service';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {ModalService} from '../_helpers/services/modal.service';
|
||||
import {Wallet} from '../_helpers/models/wallet.model';
|
||||
import {MoneyToIntPipe} from '../_helpers/pipes/money-to-int.pipe';
|
||||
import {IntToMoneyPipe} from '../_helpers/pipes/int-to-money.pipe';
|
||||
import BigNumber from 'bignumber.js';
|
||||
import {Subscription} from "rxjs";
|
||||
|
||||
@Component({
|
||||
selector: 'app-assign-alias',
|
||||
templateUrl: './assign-alias.component.html',
|
||||
styleUrls: ['./assign-alias.component.scss']
|
||||
})
|
||||
export class AssignAliasComponent implements OnInit, OnDestroy {
|
||||
|
||||
wallet: Wallet;
|
||||
assignForm = new FormGroup({
|
||||
name: new FormControl('', [Validators.required, Validators.pattern(/^@?[a-z0-9\.\-]{6,25}$/)]),
|
||||
comment: new FormControl('')
|
||||
});
|
||||
assignFormSubscription: Subscription;
|
||||
alias = {
|
||||
name: '',
|
||||
fee: this.variablesService.default_fee,
|
||||
price: new BigNumber(0),
|
||||
reward: '0',
|
||||
rewardOriginal: '0',
|
||||
comment: '',
|
||||
exists: false
|
||||
};
|
||||
canRegister = false;
|
||||
notEnoughMoney = false;
|
||||
|
||||
constructor(
|
||||
private ngZone: NgZone,
|
||||
private location: Location,
|
||||
private router: Router,
|
||||
private backend: BackendService,
|
||||
private variablesService: VariablesService,
|
||||
private modalService: ModalService,
|
||||
private moneyToInt: MoneyToIntPipe,
|
||||
private intToMoney: IntToMoneyPipe
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.wallet = this.variablesService.currentWallet;
|
||||
this.assignFormSubscription = this.assignForm.get('name').valueChanges.subscribe(value => {
|
||||
this.canRegister = false;
|
||||
this.alias.exists = false;
|
||||
const newName = value.toLowerCase().replace('@', '');
|
||||
if (!(this.assignForm.controls['name'].errors && this.assignForm.controls['name'].errors.hasOwnProperty('pattern')) && newName.length >= 6 && newName.length <= 25) {
|
||||
this.backend.getAliasByName(newName, status => {
|
||||
this.ngZone.run(() => {
|
||||
this.alias.exists = status;
|
||||
});
|
||||
if (!status) {
|
||||
this.alias.price = new BigNumber(0);
|
||||
this.backend.getAliasCoast(newName, (statusPrice, dataPrice) => {
|
||||
this.ngZone.run(() => {
|
||||
if (statusPrice) {
|
||||
this.alias.price = BigNumber.sum(dataPrice['coast'], this.variablesService.default_fee_big);
|
||||
}
|
||||
this.notEnoughMoney = this.alias.price.isGreaterThan(this.wallet.unlocked_balance);
|
||||
this.alias.reward = this.intToMoney.transform(this.alias.price, false);
|
||||
this.alias.rewardOriginal = this.intToMoney.transform(dataPrice['coast'], false);
|
||||
this.canRegister = !this.notEnoughMoney;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.notEnoughMoney = false;
|
||||
this.alias.reward = '0';
|
||||
this.alias.rewardOriginal = '0';
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.notEnoughMoney = false;
|
||||
this.alias.reward = '0';
|
||||
this.alias.rewardOriginal = '0';
|
||||
}
|
||||
this.alias.name = newName;
|
||||
});
|
||||
}
|
||||
|
||||
assignAlias() {
|
||||
const alias = this.backend.getWalletAlias(this.wallet.address);
|
||||
if (alias.hasOwnProperty('name')) {
|
||||
this.modalService.prepareModal('info', 'ASSIGN_ALIAS.ONE_ALIAS');
|
||||
} else {
|
||||
this.alias.comment = this.assignForm.get('comment').value;
|
||||
this.backend.registerAlias(this.wallet.wallet_id, this.alias.name, this.wallet.address, this.alias.fee, this.alias.comment, this.alias.rewardOriginal, (status, data) => {
|
||||
if (status) {
|
||||
this.variablesService.aliasesUnconfirmed.push({tx_hash: data.tx_hash, name: this.alias.name});
|
||||
this.wallet.wakeAlias = true;
|
||||
this.modalService.prepareModal('info', 'ASSIGN_ALIAS.REQUEST_ADD_REG');
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/wallet/' + this.wallet.wallet_id]);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.assignFormSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,9 @@ export class CreateWalletComponent implements OnInit {
|
|||
}
|
||||
|
||||
createWallet() {
|
||||
this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});
|
||||
});
|
||||
}
|
||||
|
||||
saveWallet() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<div class="content">
|
||||
|
||||
<div class="head">
|
||||
<div class="breadcrumbs">
|
||||
<span [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">{{ wallet.name }}</span>
|
||||
<span>{{ 'BREADCRUMBS.EDIT_ALIAS' | translate }}</span>
|
||||
</div>
|
||||
<button class="back-btn" (click)="back()">
|
||||
<i class="icon back"></i>
|
||||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form class="form-edit">
|
||||
|
||||
<div class="input-block alias-name">
|
||||
<label for="alias-name">
|
||||
{{ 'EDIT_ALIAS.NAME.LABEL' | translate }}
|
||||
</label>
|
||||
<input type="text" id="alias-name" [value]="alias.name" placeholder="{{ 'EDIT_ALIAS.NAME.PLACEHOLDER' | translate }}" readonly>
|
||||
</div>
|
||||
|
||||
<div class="input-block textarea">
|
||||
<label for="alias-comment">
|
||||
{{ 'EDIT_ALIAS.COMMENT.LABEL' | translate }}
|
||||
</label>
|
||||
<textarea id="alias-comment" [(ngModel)]="alias.comment" [ngModelOptions]="{standalone: true}" placeholder="{{ 'EDIT_ALIAS.COMMENT.PLACEHOLDER' | translate }}"></textarea>
|
||||
<div class="error-block" *ngIf="alias.comment.length > 0 && notEnoughMoney">
|
||||
{{ 'EDIT_ALIAS.FORM_ERRORS.NO_MONEY' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alias-cost">{{ "EDIT_ALIAS.COST" | translate : {value: variablesService.default_fee, currency: variablesService.defaultCurrency} }}</div>
|
||||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="blue-button" (click)="updateAlias()" [disabled]="notEnoughMoney || oldAliasComment === alias.comment">{{ 'EDIT_ALIAS.BUTTON_EDIT' | translate }}</button>
|
||||
<button type="button" class="blue-button" (click)="back()">{{ 'EDIT_ALIAS.BUTTON_CANCEL' | translate }}</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.form-edit {
|
||||
margin: 2.4rem 0;
|
||||
|
||||
.alias-name {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.alias-cost {
|
||||
font-size: 1.3rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.wrap-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 2.5rem -0.7rem;
|
||||
|
||||
button {
|
||||
margin: 0 0.7rem;
|
||||
width: 15rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EditAliasComponent } from './edit-alias.component';
|
||||
|
||||
describe('EditAliasComponent', () => {
|
||||
let component: EditAliasComponent;
|
||||
let fixture: ComponentFixture<EditAliasComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ EditAliasComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(EditAliasComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
import {Component, NgZone, OnInit} from '@angular/core';
|
||||
import {Location} from '@angular/common';
|
||||
import {Router} from '@angular/router';
|
||||
import {BackendService} from "../_helpers/services/backend.service";
|
||||
import {VariablesService} from "../_helpers/services/variables.service";
|
||||
import {ModalService} from '../_helpers/services/modal.service';
|
||||
import {Wallet} from "../_helpers/models/wallet.model";
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-alias',
|
||||
templateUrl: './edit-alias.component.html',
|
||||
styleUrls: ['./edit-alias.component.scss']
|
||||
})
|
||||
export class EditAliasComponent implements OnInit {
|
||||
|
||||
wallet: Wallet;
|
||||
alias: any;
|
||||
oldAliasComment: 'string';
|
||||
notEnoughMoney: boolean;
|
||||
requestProcessing = false;
|
||||
|
||||
constructor(
|
||||
private location: Location,
|
||||
private router: Router,
|
||||
private backend: BackendService,
|
||||
private variablesService: VariablesService,
|
||||
private modalService: ModalService,
|
||||
private ngZone: NgZone
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.wallet = this.variablesService.currentWallet;
|
||||
const alias = this.backend.getWalletAlias(this.wallet.address);
|
||||
this.alias = {
|
||||
name: alias.name,
|
||||
address: alias.address,
|
||||
comment: alias.comment
|
||||
};
|
||||
this.oldAliasComment = alias.comment;
|
||||
this.notEnoughMoney = this.wallet.unlocked_balance.isLessThan(this.variablesService.default_fee_big);
|
||||
}
|
||||
|
||||
updateAlias() {
|
||||
if (this.requestProcessing || this.notEnoughMoney || this.oldAliasComment === this.alias.comment) {
|
||||
return;
|
||||
}
|
||||
this.requestProcessing = true;
|
||||
this.backend.updateAlias(this.wallet.wallet_id, this.alias, this.variablesService.default_fee, (status) => {
|
||||
if (status) {
|
||||
this.modalService.prepareModal('success', '');
|
||||
this.wallet.alias['comment'] = this.alias.comment;
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/wallet/' + this.wallet.wallet_id]);
|
||||
});
|
||||
}
|
||||
this.requestProcessing = false;
|
||||
});
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,9 @@
|
|||
</tr>
|
||||
<tr class="transaction-details" [class.open]="index === openedDetails">
|
||||
<td colspan="5">
|
||||
<app-transaction-details *ngIf="index === openedDetails" [transaction]="item" [sizes]="calculatedWidth"></app-transaction-details>
|
||||
<ng-container *ngIf="index === openedDetails">
|
||||
<app-transaction-details [transaction]="item" [sizes]="calculatedWidth"></app-transaction-details>
|
||||
</ng-container>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import {Component, OnInit, OnDestroy, AfterViewChecked, ViewChild, ElementRef} from '@angular/core';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
import {ActivatedRoute} from '@angular/router';
|
||||
|
||||
@Component({
|
||||
selector: 'app-history',
|
||||
|
|
@ -7,14 +8,21 @@ import {VariablesService} from '../_helpers/services/variables.service';
|
|||
styleUrls: ['./history.component.scss']
|
||||
})
|
||||
export class HistoryComponent implements OnInit, OnDestroy, AfterViewChecked {
|
||||
|
||||
parentRouting;
|
||||
openedDetails = false;
|
||||
calculatedWidth = [];
|
||||
@ViewChild('head') head: ElementRef;
|
||||
|
||||
constructor(private variablesService: VariablesService) {}
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private variablesService: VariablesService
|
||||
) {}
|
||||
|
||||
ngOnInit() {}
|
||||
ngOnInit() {
|
||||
this.parentRouting = this.route.parent.params.subscribe(() => {
|
||||
this.openedDetails = false;
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
this.calculateWidth();
|
||||
|
|
@ -48,6 +56,8 @@ export class HistoryComponent implements OnInit, OnDestroy, AfterViewChecked {
|
|||
this.calculatedWidth.push(this.head.nativeElement.childNodes[4].clientWidth);
|
||||
}
|
||||
|
||||
ngOnDestroy() {}
|
||||
ngOnDestroy() {
|
||||
this.parentRouting.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ export class LoginComponent implements OnInit, OnDestroy {
|
|||
open_data['wi'].mined_total,
|
||||
open_data['wi'].tracking_hey
|
||||
);
|
||||
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
|
||||
if (open_data.recent_history && open_data.recent_history.history) {
|
||||
new_wallet.prepareHistory(open_data.recent_history.history);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ export class OpenWalletComponent implements OnInit, OnDestroy {
|
|||
open_data['wi'].mined_total,
|
||||
open_data['wi'].tracking_hey
|
||||
);
|
||||
new_wallet.alias = this.backend.getWalletAlias(new_wallet.address);
|
||||
if (open_data.recent_history && open_data.recent_history.history) {
|
||||
new_wallet.prepareHistory(open_data.recent_history.history);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,9 @@ export class RestoreWalletComponent implements OnInit {
|
|||
|
||||
|
||||
createWallet() {
|
||||
this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/seed-phrase'], {queryParams: {wallet_id: this.wallet.id}});
|
||||
});
|
||||
}
|
||||
|
||||
saveWallet() {
|
||||
|
|
@ -80,6 +82,7 @@ export class RestoreWalletComponent implements OnInit {
|
|||
restore_data['wi'].mined_total,
|
||||
restore_data['wi'].tracking_hey
|
||||
);
|
||||
this.variablesService.opening_wallet.alias = this.backend.getWalletAlias(this.variablesService.opening_wallet.address);
|
||||
if (restore_data.recent_history && restore_data.recent_history.history) {
|
||||
this.variablesService.opening_wallet.prepareHistory(restore_data.recent_history.history);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
<h3 class="seed-phrase-title">{{ 'SEED_PHRASE.TITLE' | translate }}</h3>
|
||||
|
||||
<div class="seed-phrase-content">
|
||||
<div class="seed-phrase-content" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
|
||||
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
|
||||
<div class="word">{{(index + 1) + '. ' + word}}</div>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<span class="balance">{{wallet.balance | intToMoney : '3' }} {{variablesService.defaultCurrency}}</span>
|
||||
</div>
|
||||
<div class="sidebar-account-row account-alias">
|
||||
<span>{{wallet.alias}}</span>
|
||||
<span>{{wallet.alias['name']}}</span>
|
||||
<span>$ {{wallet.getMoneyEquivalent(variablesService.moneyEquivalent) | intToMoney | number : '1.2-2'}}</span>
|
||||
</div>
|
||||
<div class="sidebar-account-row account-staking" *ngIf="!(!wallet.loaded && variablesService.daemon_state === 2)">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import {Component, OnInit, OnDestroy} from '@angular/core';
|
||||
import {Component, NgZone, OnInit, OnDestroy} from '@angular/core';
|
||||
import {ActivatedRoute, NavigationStart, Router} from '@angular/router';
|
||||
import {VariablesService} from '../_helpers/services/variables.service';
|
||||
|
||||
|
|
@ -15,9 +15,9 @@ export class SidebarComponent implements OnInit, OnDestroy {
|
|||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private variablesService: VariablesService
|
||||
) {
|
||||
}
|
||||
private variablesService: VariablesService,
|
||||
private ngZone: NgZone
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.router.url.indexOf('/wallet/') !== -1) {
|
||||
|
|
@ -47,14 +47,15 @@ export class SidebarComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.walletSubRouting.unsubscribe();
|
||||
}
|
||||
|
||||
logOut() {
|
||||
this.variablesService.stopCountdown();
|
||||
this.variablesService.appPass = '';
|
||||
this.router.navigate(['/login'], {queryParams: {type: 'auth'}});
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/login'], {queryParams: {type: 'auth'}});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.walletSubRouting.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
<div class="content">
|
||||
|
||||
<div class="head">
|
||||
<div class="breadcrumbs">
|
||||
<span [routerLink]="['/wallet/' + wallet.wallet_id + '/history']">{{ wallet.name }}</span>
|
||||
<span>{{ 'BREADCRUMBS.TRANSFER_ALIAS' | translate }}</span>
|
||||
</div>
|
||||
<button class="back-btn" (click)="back()">
|
||||
<i class="icon back"></i>
|
||||
<span>{{ 'COMMON.BACK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form class="form-transfer">
|
||||
|
||||
<div class="input-block alias-name">
|
||||
<label for="alias-name">
|
||||
{{ 'EDIT_ALIAS.NAME.LABEL' | translate }}
|
||||
</label>
|
||||
<input type="text" id="alias-name" [value]="alias.name" placeholder="{{ 'EDIT_ALIAS.NAME.PLACEHOLDER' | translate }}" readonly>
|
||||
</div>
|
||||
|
||||
<div class="input-block textarea">
|
||||
<label for="alias-comment">
|
||||
{{ 'EDIT_ALIAS.COMMENT.LABEL' | translate }}
|
||||
</label>
|
||||
<textarea id="alias-comment" [value]="alias.comment" placeholder="{{ 'EDIT_ALIAS.COMMENT.PLACEHOLDER' | translate }}" readonly></textarea>
|
||||
</div>
|
||||
|
||||
<div class="input-block alias-transfer-address">
|
||||
<label for="alias-transfer">
|
||||
{{ 'TRANSFER_ALIAS.ADDRESS.LABEL' | translate }}
|
||||
</label>
|
||||
<input type="text" id="alias-transfer" [(ngModel)]="transferAddress" [ngModelOptions]="{standalone: true}" (ngModelChange)="changeAddress()" placeholder="{{ 'TRANSFER_ALIAS.ADDRESS.PLACEHOLDER' | translate }}">
|
||||
<div class="error-block" *ngIf="transferAddress.length > 0 && (transferAddressAlias || !transferAddressValid || (transferAddressValid && !permissionSend) || notEnoughMoney)">
|
||||
<div *ngIf="!transferAddressValid">
|
||||
{{ 'TRANSFER_ALIAS.FORM_ERRORS.WRONG_ADDRESS' | translate }}
|
||||
</div>
|
||||
<div *ngIf="transferAddressAlias || (transferAddressValid && !permissionSend)">
|
||||
{{ 'TRANSFER_ALIAS.FORM_ERRORS.ALIAS_EXISTS' | translate }}
|
||||
</div>
|
||||
<div *ngIf="notEnoughMoney">
|
||||
{{ 'TRANSFER_ALIAS.FORM_ERRORS.NO_MONEY' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alias-cost">{{ "TRANSFER_ALIAS.COST" | translate : {value: variablesService.default_fee, currency: variablesService.defaultCurrency} }}</div>
|
||||
|
||||
<div class="wrap-buttons">
|
||||
<button type="button" class="blue-button" (click)="transferAlias()" [disabled]="transferAddressAlias || !transferAddressValid || notEnoughMoney">{{ 'TRANSFER_ALIAS.BUTTON_TRANSFER' | translate }}</button>
|
||||
<button type="button" class="blue-button" (click)="back()">{{ 'TRANSFER_ALIAS.BUTTON_CANCEL' | translate }}</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
.form-transfer {
|
||||
margin: 2.4rem 0;
|
||||
|
||||
.alias-name {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.alias-cost {
|
||||
font-size: 1.3rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.wrap-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 2.5rem -0.7rem;
|
||||
|
||||
button {
|
||||
margin: 0 0.7rem;
|
||||
width: 15rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TransferAliasComponent } from './transfer-alias.component';
|
||||
|
||||
describe('TransferAliasComponent', () => {
|
||||
let component: TransferAliasComponent;
|
||||
let fixture: ComponentFixture<TransferAliasComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ TransferAliasComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(TransferAliasComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
import {Component, NgZone, OnInit} from '@angular/core';
|
||||
import {Location} from "@angular/common";
|
||||
import {Router} from "@angular/router";
|
||||
import {BackendService} from "../_helpers/services/backend.service";
|
||||
import {VariablesService} from "../_helpers/services/variables.service";
|
||||
import {ModalService} from "../_helpers/services/modal.service";
|
||||
import {Wallet} from "../_helpers/models/wallet.model";
|
||||
|
||||
@Component({
|
||||
selector: 'app-transfer-alias',
|
||||
templateUrl: './transfer-alias.component.html',
|
||||
styleUrls: ['./transfer-alias.component.scss']
|
||||
})
|
||||
export class TransferAliasComponent implements OnInit {
|
||||
|
||||
wallet: Wallet;
|
||||
alias: any;
|
||||
transferAddress = '';
|
||||
transferAddressValid: boolean;
|
||||
transferAddressAlias: boolean;
|
||||
permissionSend: boolean;
|
||||
notEnoughMoney: boolean;
|
||||
requestProcessing = false;
|
||||
|
||||
constructor(
|
||||
private location: Location,
|
||||
private router: Router,
|
||||
private backend: BackendService,
|
||||
private variablesService: VariablesService,
|
||||
private modalService: ModalService,
|
||||
private ngZone: NgZone
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.wallet = this.variablesService.currentWallet;
|
||||
const alias = this.backend.getWalletAlias(this.wallet.address);
|
||||
this.alias = {
|
||||
name: alias.name,
|
||||
address: alias.address,
|
||||
comment: alias.comment,
|
||||
tracking_key: alias.tracking_key
|
||||
};
|
||||
this.notEnoughMoney = this.wallet.unlocked_balance.isLessThan(this.variablesService.default_fee_big);
|
||||
}
|
||||
|
||||
changeAddress() {
|
||||
this.backend.validateAddress(this.transferAddress, status => {
|
||||
this.transferAddressValid = status;
|
||||
if (status) {
|
||||
this.backend.getPoolInfo((statusPool, dataPool) => {
|
||||
if (dataPool.hasOwnProperty('aliases_que') && dataPool.aliases_que.length) {
|
||||
this.setStatus(!~dataPool.aliases_que.searchBy('address', this.transferAddress));
|
||||
} else {
|
||||
this.setStatus(status);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.setStatus(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setStatus(statusSet) {
|
||||
this.permissionSend = statusSet;
|
||||
if (statusSet) {
|
||||
this.backend.getAliasByAddress(this.transferAddress, (status, data) => {
|
||||
this.ngZone.run(() => {
|
||||
if (status) {
|
||||
this.transferAddressAlias = true;
|
||||
this.permissionSend = false;
|
||||
} else {
|
||||
this.transferAddressAlias = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.ngZone.run(() => {
|
||||
this.transferAddressAlias = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
transferAlias() {
|
||||
if (this.requestProcessing || !this.permissionSend || !this.transferAddressValid || this.notEnoughMoney) {
|
||||
return;
|
||||
}
|
||||
this.requestProcessing = true;
|
||||
const newAlias = {
|
||||
name: this.alias.name,
|
||||
address: this.transferAddress,
|
||||
comment: this.alias.comment,
|
||||
tracking_key: this.alias.tracking_key
|
||||
};
|
||||
this.backend.updateAlias(this.wallet.wallet_id, newAlias, this.variablesService.default_fee, (status, data) => {
|
||||
if (status && data.hasOwnProperty('success') && data.success) {
|
||||
this.modalService.prepareModal('info', 'TRANSFER_ALIAS.REQUEST_SEND_REG');
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/wallet/' + this.wallet.wallet_id]);
|
||||
});
|
||||
}
|
||||
this.requestProcessing = false;
|
||||
});
|
||||
}
|
||||
|
||||
back() {
|
||||
this.location.back();
|
||||
}
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
<label for="seed-phrase">{{ 'WALLET_DETAILS.LABEL_SEED_PHRASE' | translate }}</label>
|
||||
<div class="seed-phrase" id="seed-phrase">
|
||||
<div class="seed-phrase-hint" (click)="showSeedPhrase()" *ngIf="!showSeed">{{ 'WALLET_DETAILS.SEED_PHRASE_HINT' | translate }}</div>
|
||||
<div class="seed-phrase-content" *ngIf="showSeed">
|
||||
<div class="seed-phrase-content" *ngIf="showSeed" (contextmenu)="variablesService.onContextMenuOnlyCopy($event, seedPhrase)">
|
||||
<ng-container *ngFor="let word of seedPhrase.split(' '); let index = index">
|
||||
<div class="word">{{(index + 1) + '. ' + word}}</div>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@ export class WalletDetailsComponent implements OnInit, OnDestroy {
|
|||
onSubmitEdit() {
|
||||
if (this.detailsForm.value) {
|
||||
this.variablesService.currentWallet.name = this.detailsForm.get('name').value;
|
||||
this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);
|
||||
this.ngZone.run(() => {
|
||||
this.router.navigate(['/wallet/' + this.variablesService.currentWallet.wallet_id]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,16 @@
|
|||
<div class="header">
|
||||
<div>
|
||||
<h3>{{variablesService.currentWallet.name}}</h3>
|
||||
<button (click)="openInBrowser('docs.zano.org/docs/how-to-get-alias')">
|
||||
<!--<button (click)="openInBrowser('docs.zano.org/docs/how-to-get-alias')">-->
|
||||
<button [routerLink]="['/assign-alias']" *ngIf="!variablesService.currentWallet.alias.hasOwnProperty('name')">
|
||||
<i class="icon account"></i>
|
||||
<span>{{ 'WALLET.REGISTER_ALIAS' | translate }}</span>
|
||||
</button>
|
||||
<div class="alias" *ngIf="variablesService.currentWallet.alias.hasOwnProperty('name')">
|
||||
<span>{{variablesService.currentWallet.alias['name']}}</span>
|
||||
<i class="icon edit" [routerLink]="['/edit-alias']"></i>
|
||||
<i class="icon transfer" [routerLink]="['/transfer-alias']"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button [routerLink]="['/details']" routerLinkActive="active">
|
||||
|
|
@ -22,7 +28,7 @@
|
|||
<i #copyIcon class="icon copy" (click)="copyAddress()"></i>
|
||||
</div>
|
||||
<div class="balance">
|
||||
<span [tooltip]="getTooltip()" [placement]="'bottom'" [tooltipClass]="'balance-tooltip'" [delay]="500" [timeout]="1000">{{variablesService.currentWallet.balance | intToMoney : '3'}} {{variablesService.defaultCurrency}}</span>
|
||||
<span [tooltip]="getTooltip()" [placement]="'bottom'" [tooltipClass]="'balance-tooltip'" [delay]="300" [timeout]="0">{{variablesService.currentWallet.balance | intToMoney : '3'}} {{variablesService.defaultCurrency}}</span>
|
||||
<span>$ {{variablesService.currentWallet.getMoneyEquivalent(variablesService.moneyEquivalent) | intToMoney | number : '1.2-2'}}</span>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
|
|
|
|||
|
|
@ -57,6 +57,27 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alias {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 1.3rem;
|
||||
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
margin-right: 1.2rem;
|
||||
width: 1.7rem;
|
||||
height: 1.7rem;
|
||||
|
||||
&.edit {
|
||||
mask: url(../../assets/icons/details.svg) no-repeat center;
|
||||
}
|
||||
|
||||
&.transfer {
|
||||
mask: url(../../assets/icons/send.svg) no-repeat center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {BackendService} from '../_helpers/services/backend.service';
|
|||
import {TranslateService} from '@ngx-translate/core';
|
||||
import {IntToMoneyPipe} from '../_helpers/pipes/int-to-money.pipe';
|
||||
import {BigNumber} from 'bignumber.js';
|
||||
import {Subscription} from "rxjs";
|
||||
|
||||
@Component({
|
||||
selector: 'app-wallet',
|
||||
|
|
@ -59,6 +60,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
active: false
|
||||
}
|
||||
];
|
||||
aliasSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
|
|
@ -69,8 +71,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
private ngZone: NgZone,
|
||||
private translate: TranslateService,
|
||||
private intToMoneyPipe: IntToMoneyPipe
|
||||
) {
|
||||
}
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.subRouting = this.route.params.subscribe(params => {
|
||||
|
|
@ -80,6 +81,14 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
this.tabs[i].active = (this.tabs[i].link === '/' + this.route.snapshot.firstChild.url[0].path);
|
||||
}
|
||||
});
|
||||
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
|
||||
this.variablesService.currentWallet.wakeAlias = false;
|
||||
}
|
||||
this.aliasSubscription = this.variablesService.getAliasChangedEvent.subscribe(() => {
|
||||
if (this.variablesService.currentWallet.alias.hasOwnProperty('name')) {
|
||||
this.variablesService.currentWallet.wakeAlias = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
changeTab(index) {
|
||||
|
|
@ -90,7 +99,9 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
tab.active = false;
|
||||
});
|
||||
this.tabs[index].active = true;
|
||||
this.router.navigate(['wallet/' + this.walletID + this.tabs[index].link]);
|
||||
this.ngZone.run( () => {
|
||||
this.router.navigate(['wallet/' + this.walletID + this.tabs[index].link]);
|
||||
});
|
||||
}
|
||||
|
||||
copyAddress() {
|
||||
|
|
@ -129,6 +140,7 @@ export class WalletComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnDestroy() {
|
||||
this.subRouting.unsubscribe();
|
||||
this.aliasSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@
|
|||
"OPEN_WALLET": "Open existing wallet",
|
||||
"RESTORE_WALLET": "Restore from backup",
|
||||
"WALLET_DETAILS": "Wallet details",
|
||||
"ASSIGN_ALIAS": "Assign alias",
|
||||
"EDIT_ALIAS": "Edit alias",
|
||||
"TRANSFER_ALIAS": "Transfer alias",
|
||||
"CONTRACTS": "Contracts",
|
||||
"NEW_PURCHASE": "New purchase",
|
||||
"OLD_PURCHASE": "Purchase"
|
||||
|
|
@ -148,6 +151,68 @@
|
|||
"NAME_DUPLICATE": "Name is duplicate."
|
||||
}
|
||||
},
|
||||
"ASSIGN_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"PLACEHOLDER": "@ Enter alias",
|
||||
"TOOLTIP": "An alias is a shortened form or your account. An alias can only include Latin letters, numbers and characters “.” and “-”. It must start with “@”."
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment",
|
||||
"TOOLTIP": "The comment will be visible to anyone who wants to make a payment to your alias. You can provide details about your business, contacts, or include any text. Comments can be edited later."
|
||||
},
|
||||
"COST": "Cost to create alias {{value}} {{currency}}",
|
||||
"BUTTON_ASSIGN": "Assign",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"FORM_ERRORS": {
|
||||
"NAME_REQUIRED": "Name is required.",
|
||||
"NAME_WRONG": "Alias has wrong name.",
|
||||
"NAME_LENGTH": "The alias must be 6-25 characters long.",
|
||||
"NAME_EXISTS": "Alias name already exists."
|
||||
},
|
||||
"ONE_ALIAS": "You can create only one alias per wallet",
|
||||
"REQUEST_ADD_REG": "The alias will be assigned within 10 minutes"
|
||||
},
|
||||
"EDIT_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"NO_MONEY": "You do not have enough funds to change the comment to this alias"
|
||||
},
|
||||
"COST": "Cost to edit alias {{value}} {{currency}}",
|
||||
"BUTTON_EDIT": "Edit",
|
||||
"BUTTON_CANCEL": "Cancel"
|
||||
},
|
||||
"TRANSFER_ALIAS": {
|
||||
"NAME": {
|
||||
"LABEL": "Unique name",
|
||||
"PLACEHOLDER": "@ Enter alias"
|
||||
},
|
||||
"COMMENT": {
|
||||
"LABEL": "Comment",
|
||||
"PLACEHOLDER": "Enter comment"
|
||||
},
|
||||
"ADDRESS": {
|
||||
"LABEL": "The account to which the alias will be transferred",
|
||||
"PLACEHOLDER": "Enter account number"
|
||||
},
|
||||
"FORM_ERRORS": {
|
||||
"WRONG_ADDRESS": "No wallet with this account exists",
|
||||
"ALIAS_EXISTS": "This account already has an alias",
|
||||
"NO_MONEY": "You do not have enough funds to transfer this alias"
|
||||
},
|
||||
"COST": "Cost to transfer alias {{value}} {{currency}}",
|
||||
"BUTTON_TRANSFER": "Transfer",
|
||||
"BUTTON_CANCEL": "Cancel",
|
||||
"REQUEST_SEND_REG": "The alias will be transferred within 10 minutes"
|
||||
},
|
||||
"SEND": {
|
||||
"ADDRESS": "Address",
|
||||
"AMOUNT": "Amount",
|
||||
|
|
@ -190,6 +255,8 @@
|
|||
"UNDEFINED": "Undefined",
|
||||
"COMPLETE_BUYER": "Successfully complete contract, return remaining pledge",
|
||||
"COMPLETE_SELLER": "Successfully complete contract, receive payment on contract, and return pledge",
|
||||
"CREATE_ALIAS": "Fee for assigning alias",
|
||||
"UPDATE_ALIAS": "Fee for editing alias",
|
||||
"MINED": "Mined funds",
|
||||
"CREATE_CONTRACT": "Send contract offer",
|
||||
"PLEDGE_CONTRACT": "Make pledge on offer",
|
||||
|
|
@ -370,7 +437,14 @@
|
|||
"FILE_RESTORED": "The wallet file was corrupted. We have recovered the keys and the wallet from the blockchain",
|
||||
"FILE_NOT_FOUND": "File not found",
|
||||
"FILE_EXIST": "A file with that name already exists. Enter another name to save the file under",
|
||||
"FILE_NOT_SAVED": "You cannot save a wallet file in this folder. Please choose another folder."
|
||||
"FILE_NOT_SAVED": "You cannot save a wallet file in this folder. Please choose another folder.",
|
||||
"TX_TYPE_NORMAL": "Error. The payment from the wallet",
|
||||
"TX_TYPE_NORMAL_TO": "to",
|
||||
"TX_TYPE_NORMAL_END": "was not completed.",
|
||||
"TX_TYPE_NEW_ALIAS": "Error. Failed to register alias to safe",
|
||||
"TX_TYPE_NEW_ALIAS_END": "Please try again.",
|
||||
"TX_TYPE_UPDATE_ALIAS": "Error. Failed to change comment to alias in safe",
|
||||
"TX_TYPE_COIN_BASE": "Error. The payment was not completed."
|
||||
},
|
||||
"CONTEXT_MENU": {
|
||||
"COPY": "copy",
|
||||
|
|
|
|||
|
|
@ -141,8 +141,8 @@ button {
|
|||
width: 100%;
|
||||
min-width: 100%;
|
||||
height: 100%;
|
||||
min-height: 7rem;
|
||||
max-height: 7rem;
|
||||
min-height: 7.5rem;
|
||||
max-height: 7.5rem;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
|
||||
|
|
@ -157,6 +157,7 @@ button {
|
|||
font-size: 1rem;
|
||||
line-height: 1.4rem;
|
||||
align-self: flex-end;
|
||||
text-align: right;
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed(redTextColor);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
app-main, app-create-wallet, app-open-wallet, app-restore-wallet, app-seed-phrase, app-wallet-details, app-settings, app-login {
|
||||
app-main, app-create-wallet, app-open-wallet, app-restore-wallet, app-seed-phrase, app-wallet-details, app-assign-alias, app-edit-alias, app-transfer-alias, app-settings, app-login {
|
||||
flex: 1 1 auto;
|
||||
padding: 3rem;
|
||||
min-width: 85rem;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,16 @@ app-wallet {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alias {
|
||||
|
||||
.icon {
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed(blueTextColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.address {
|
||||
|
|
|
|||
|
|
@ -124,6 +124,8 @@ namespace nodetool
|
|||
HANDLE_INVOKE_T2(COMMAND_REQUEST_STAT_INFO, &node_server::handle_get_stat_info)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_NETWORK_STATE, &node_server::handle_get_network_state)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_PEER_ID, &node_server::handle_get_peer_id)
|
||||
HANDLE_INVOKE_T2(COMMAND_REQUEST_LOG, &node_server::handle_request_log)
|
||||
HANDLE_INVOKE_T2(COMMAND_SET_LOG_LEVEL, &node_server::handle_set_log_level)
|
||||
#endif
|
||||
CHAIN_INVOKE_MAP_TO_OBJ_FORCE_CONTEXT(m_payload_handler, typename t_payload_net_handler::connection_context&)
|
||||
END_INVOKE_MAP2()
|
||||
|
|
@ -137,6 +139,8 @@ namespace nodetool
|
|||
int handle_get_stat_info(int command, typename COMMAND_REQUEST_STAT_INFO::request& arg, typename COMMAND_REQUEST_STAT_INFO::response& rsp, p2p_connection_context& context);
|
||||
int handle_get_network_state(int command, COMMAND_REQUEST_NETWORK_STATE::request& arg, COMMAND_REQUEST_NETWORK_STATE::response& rsp, p2p_connection_context& context);
|
||||
int handle_get_peer_id(int command, COMMAND_REQUEST_PEER_ID::request& arg, COMMAND_REQUEST_PEER_ID::response& rsp, p2p_connection_context& context);
|
||||
int handle_request_log(int command, COMMAND_REQUEST_LOG::request& arg, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context);
|
||||
int handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& arg, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context);
|
||||
private:
|
||||
#endif
|
||||
bool init_config();
|
||||
|
|
|
|||
|
|
@ -1039,6 +1039,7 @@ namespace nodetool
|
|||
rsp.connections_count = m_net_server.get_config_object().get_connections_count();
|
||||
rsp.incoming_connections_count = rsp.connections_count - get_outgoing_connections_count();
|
||||
rsp.version = PROJECT_VERSION_LONG;
|
||||
rsp.current_log_size = tools::get_log_file_size();
|
||||
m_payload_handler.get_stat_info(arg.pr, rsp.payload_info);
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1080,7 +1081,44 @@ namespace nodetool
|
|||
rsp.my_id = m_config.m_peer_id;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_request_log(int command, COMMAND_REQUEST_LOG::request& req, COMMAND_REQUEST_LOG::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if (!check_trust(req.tr))
|
||||
{
|
||||
drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rsp.current_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
tools::get_log_chunk_gzipped(req.log_chunk_offset, req.log_chunk_size, rsp.log_chunk, rsp.error);
|
||||
rsp.current_log_size = tools::get_log_file_size();
|
||||
|
||||
return 1;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
int node_server<t_payload_net_handler>::handle_set_log_level(int command, COMMAND_SET_LOG_LEVEL::request& req, COMMAND_SET_LOG_LEVEL::response& rsp, p2p_connection_context& context)
|
||||
{
|
||||
if (!check_trust(req.tr))
|
||||
{
|
||||
drop_connection(context);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rsp.old_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
log_space::get_set_log_detalisation_level(true, static_cast<int>(req.new_log_level));
|
||||
rsp.current_log_level = static_cast<int64_t>(log_space::get_set_log_detalisation_level());
|
||||
|
||||
if (rsp.old_log_level != rsp.current_log_level)
|
||||
{
|
||||
LOG_PRINT_CC(context, "log level changed by debug command: " << rsp.old_log_level << " -> " << rsp.current_log_level, LOG_LEVEL_0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // #ifdef ALLOW_DEBUG_COMMANDS
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
void node_server<t_payload_net_handler>::request_callback(const epee::net_utils::connection_context_base& context)
|
||||
|
|
|
|||
|
|
@ -328,12 +328,14 @@ namespace nodetool
|
|||
std::string version;
|
||||
uint64_t connections_count;
|
||||
uint64_t incoming_connections_count;
|
||||
uint64_t current_log_size;
|
||||
payload_stat_info payload_info;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(version)
|
||||
KV_SERIALIZE(connections_count)
|
||||
KV_SERIALIZE(incoming_connections_count)
|
||||
KV_SERIALIZE(current_log_size)
|
||||
KV_SERIALIZE(payload_info)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
|
@ -397,7 +399,73 @@ namespace nodetool
|
|||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct COMMAND_REQUEST_LOG
|
||||
{
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 7;
|
||||
|
||||
struct request
|
||||
{
|
||||
proof_of_trust tr;
|
||||
uint64_t log_chunk_offset;
|
||||
uint64_t log_chunk_size;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tr)
|
||||
KV_SERIALIZE(log_chunk_offset)
|
||||
KV_SERIALIZE(log_chunk_size)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
int64_t current_log_level;
|
||||
uint64_t current_log_size;
|
||||
std::string error;
|
||||
std::string log_chunk;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(current_log_level)
|
||||
KV_SERIALIZE(current_log_size)
|
||||
KV_SERIALIZE(error)
|
||||
KV_SERIALIZE(log_chunk)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct COMMAND_SET_LOG_LEVEL
|
||||
{
|
||||
const static int ID = P2P_COMMANDS_POOL_BASE + 8;
|
||||
|
||||
struct request
|
||||
{
|
||||
proof_of_trust tr;
|
||||
int64_t new_log_level;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tr)
|
||||
KV_SERIALIZE(new_log_level)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
int64_t old_log_level;
|
||||
int64_t current_log_level;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(old_log_level)
|
||||
KV_SERIALIZE(current_log_level)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
#endif // #ifdef ALLOW_DEBUG_COMMANDS
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,9 +35,13 @@ int test_big_difficulties(const char* dataFile)
|
|||
end = n - DIFFICULTY_LAG;
|
||||
begin = end - DIFFICULTY_WINDOW;
|
||||
}
|
||||
auto stamps = vector<uint64_t>(timestamps.begin() + begin, timestamps.begin() + end);
|
||||
auto cumulative_diffs = vector<currency::wide_difficulty_type>(cumulative_difficulties.begin() + begin, cumulative_difficulties.begin() + end);
|
||||
currency::wide_difficulty_type res = currency::next_difficulty(
|
||||
vector<uint64_t>(timestamps.begin() + begin, timestamps.begin() + end),
|
||||
vector<currency::wide_difficulty_type>(cumulative_difficulties.begin() + begin, cumulative_difficulties.begin() + end), DEFAULT_TEST_DIFFICULTY_TARGET);
|
||||
stamps,
|
||||
cumulative_diffs,
|
||||
DEFAULT_TEST_DIFFICULTY_TARGET
|
||||
);
|
||||
if (res != difficulty) {
|
||||
cerr << "Wrong wide difficulty for block " << n << endl
|
||||
<< "Expected: " << difficulty << endl
|
||||
|
|
@ -90,9 +94,13 @@ int main(int argc, char *argv[]) {
|
|||
<< "Found: " << res << endl;
|
||||
return 1;
|
||||
}
|
||||
auto stamps = vector<uint64_t>(timestamps.begin() + begin, timestamps.begin() + end);
|
||||
auto cumulative_diffs = vector<currency::wide_difficulty_type>(wide_cumulative_difficulties.begin() + begin, wide_cumulative_difficulties.begin() + end);
|
||||
currency::wide_difficulty_type wide_res = currency::next_difficulty(
|
||||
vector<uint64_t>(timestamps.begin() + begin, timestamps.begin() + end),
|
||||
vector<currency::wide_difficulty_type>(wide_cumulative_difficulties.begin() + begin, wide_cumulative_difficulties.begin() + end), DEFAULT_TEST_DIFFICULTY_TARGET);
|
||||
stamps,
|
||||
cumulative_diffs,
|
||||
DEFAULT_TEST_DIFFICULTY_TARGET
|
||||
);
|
||||
if (wide_res.convert_to<uint64_t>() != res) {
|
||||
cerr << "Wrong wide difficulty for block " << n << endl
|
||||
<< "Expected: " << res << endl
|
||||
|
|
@ -110,3 +118,4 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ using namespace epee;
|
|||
#include "wallet/wallet2.h"
|
||||
#include "currency_core/blockchain_storage.h"
|
||||
|
||||
|
||||
using std::size_t;
|
||||
using std::uint64_t;
|
||||
using std::vector;
|
||||
|
||||
bool parse_file(const std::string& path, std::vector<std::vector<uint64_t>>& blocks, uint64_t reserve_size)
|
||||
{
|
||||
|
|
@ -41,11 +45,220 @@ bool parse_file(const std::string& path, std::vector<std::vector<uint64_t>>& blo
|
|||
}
|
||||
|
||||
|
||||
void run_difficulty_analysis(const std::string& path)
|
||||
{
|
||||
//hash_rate_analysis(path);
|
||||
run_emulation(path);
|
||||
#define BBR_DIFFICULTY_TARGET 120 // seconds
|
||||
#define BBR_DIFFICULTY_WINDOW 720 // blocks
|
||||
#define BBR_DIFFICULTY_LAG 15 // !!!
|
||||
#define BBR_DIFFICULTY_CUT 60 // timestamps to cut after sorting
|
||||
#define BBR_DIFFICULTY_STARTER 1
|
||||
|
||||
#define NEW_DIFFICULTY_WINDOW 360
|
||||
#define NEW_DIFFICULTY_CUT_OLD 60 // timestamps to cut after sorting on the oldest timestamps
|
||||
#define NEW_DIFFICULTY_CUT_LAST 0 // timestamps to cut after sorting on the most recent timestamps
|
||||
|
||||
const boost::multiprecision::uint256_t max128bit(std::numeric_limits<boost::multiprecision::uint128_t>::max());
|
||||
currency::wide_difficulty_type bbr_next_difficulty(std::vector<uint64_t>& timestamps, std::vector<currency::wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
{
|
||||
// timestamps - first is latest, back - is oldest timestamps
|
||||
//cutoff DIFFICULTY_LAG
|
||||
if (timestamps.size() > BBR_DIFFICULTY_WINDOW)
|
||||
{
|
||||
timestamps.resize(BBR_DIFFICULTY_WINDOW);
|
||||
cumulative_difficulties.resize(BBR_DIFFICULTY_WINDOW);
|
||||
}
|
||||
|
||||
|
||||
size_t length = timestamps.size();
|
||||
CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed");
|
||||
if (length <= 1) {
|
||||
return BBR_DIFFICULTY_STARTER;
|
||||
}
|
||||
static_assert(BBR_DIFFICULTY_WINDOW >= 2, "Window is too small");
|
||||
CHECK_AND_ASSERT_MES(length <= BBR_DIFFICULTY_WINDOW, 0, "length <= BBR_DIFFICULTY_WINDOW check failed, length=" << length);
|
||||
sort(timestamps.begin(), timestamps.end(), std::greater<uint64_t>());
|
||||
size_t cut_begin, cut_end;
|
||||
static_assert(2 * BBR_DIFFICULTY_CUT <= BBR_DIFFICULTY_WINDOW - 2, "Cut length is too large");
|
||||
if (length <= BBR_DIFFICULTY_WINDOW - 2 * BBR_DIFFICULTY_CUT) {
|
||||
cut_begin = 0;
|
||||
cut_end = length;
|
||||
}
|
||||
else {
|
||||
cut_begin = (length - (BBR_DIFFICULTY_WINDOW - 2 * BBR_DIFFICULTY_CUT) + 1) / 2;
|
||||
cut_end = cut_begin + (BBR_DIFFICULTY_WINDOW - 2 * BBR_DIFFICULTY_CUT);
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length, "validation in next_difficulty is failed");
|
||||
uint64_t time_span = timestamps[cut_begin] - timestamps[cut_end - 1];
|
||||
if (time_span == 0) {
|
||||
time_span = 1;
|
||||
}
|
||||
currency::wide_difficulty_type total_work = cumulative_difficulties[cut_begin] - cumulative_difficulties[cut_end - 1];
|
||||
boost::multiprecision::uint256_t res = (boost::multiprecision::uint256_t(total_work) * target_seconds + time_span - 1) / time_span;
|
||||
if (res > max128bit)
|
||||
return 0; // to behave like previous implementation, may be better return max128bit?
|
||||
return res.convert_to<currency::wide_difficulty_type>();
|
||||
}
|
||||
|
||||
|
||||
void get_cut_location_from_len(size_t length, size_t& cut_begin, size_t& cut_end, size_t REDEF_DIFFICULTY_WINDOW, size_t REDEF_DIFFICULTY_CUT_OLD, size_t REDEF_DIFFICULTY_CUT_LAST)
|
||||
{
|
||||
if (length <= REDEF_DIFFICULTY_WINDOW)
|
||||
{
|
||||
cut_begin = 0;
|
||||
cut_end = length;
|
||||
}
|
||||
else
|
||||
{
|
||||
cut_begin = REDEF_DIFFICULTY_WINDOW - REDEF_DIFFICULTY_CUT_LAST + 1;
|
||||
cut_end = cut_begin + (REDEF_DIFFICULTY_WINDOW - (REDEF_DIFFICULTY_CUT_OLD + REDEF_DIFFICULTY_CUT_LAST));
|
||||
}
|
||||
}
|
||||
|
||||
currency::wide_difficulty_type bbr_next_difficulty_configurable(std::vector<uint64_t>& timestamps, std::vector<currency::wide_difficulty_type>& cumulative_difficulties, size_t target_seconds, size_t REDEF_DIFFICULTY_WINDOW, size_t REDEF_DIFFICULTY_CUT_OLD, size_t REDEF_DIFFICULTY_CUT_LAST)
|
||||
{
|
||||
// timestamps - first is latest, back - is oldest timestamps
|
||||
//cutoff DIFFICULTY_LAG
|
||||
if (timestamps.size() > REDEF_DIFFICULTY_WINDOW)
|
||||
{
|
||||
timestamps.resize(REDEF_DIFFICULTY_WINDOW);
|
||||
cumulative_difficulties.resize(REDEF_DIFFICULTY_WINDOW);
|
||||
}
|
||||
|
||||
|
||||
size_t length = timestamps.size();
|
||||
CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed");
|
||||
if (length <= 1) {
|
||||
return BBR_DIFFICULTY_STARTER;
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(REDEF_DIFFICULTY_WINDOW >= 2, "Window is too small");
|
||||
CHECK_AND_ASSERT_MES(length <= REDEF_DIFFICULTY_WINDOW, 0, "length <= REDEF_DIFFICULTY_WINDOW check failed, length=" << length);
|
||||
sort(timestamps.begin(), timestamps.end(), std::greater<uint64_t>());
|
||||
size_t cut_begin, cut_end;
|
||||
CHECK_AND_ASSERT_THROW_MES( (REDEF_DIFFICULTY_CUT_OLD + REDEF_DIFFICULTY_CUT_LAST) <= REDEF_DIFFICULTY_WINDOW - 2, "Cut length is too large");
|
||||
get_cut_location_from_len(length, cut_begin, cut_end, REDEF_DIFFICULTY_WINDOW, REDEF_DIFFICULTY_CUT_OLD, REDEF_DIFFICULTY_CUT_LAST);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length, "validation in next_difficulty is failed");
|
||||
uint64_t time_span = timestamps[cut_begin] - timestamps[cut_end - 1];
|
||||
if (time_span == 0) {
|
||||
time_span = 1;
|
||||
}
|
||||
currency::wide_difficulty_type total_work = cumulative_difficulties[cut_begin] - cumulative_difficulties[cut_end - 1];
|
||||
boost::multiprecision::uint256_t res = (boost::multiprecision::uint256_t(total_work) * target_seconds + time_span - 1) / time_span;
|
||||
if (res > max128bit)
|
||||
return 0; // to behave like previous implementation, may be better return max128bit?
|
||||
return res.convert_to<currency::wide_difficulty_type>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
currency::wide_difficulty_type bbr_next_difficulty_composit(std::vector<uint64_t>& timestamps, std::vector<currency::wide_difficulty_type>& cumulative_difficulties, size_t target_seconds, size_t REDEF_DIFFICULTY_WINDOW, size_t REDEF_DIFFICULTY_CUT_OLD, size_t REDEF_DIFFICULTY_CUT_LAST)
|
||||
{
|
||||
sort(timestamps.begin(), timestamps.end(), std::greater<uint64_t>());
|
||||
std::vector<uint64_t> timestamps_local = timestamps;
|
||||
currency::wide_difficulty_type dif = bbr_next_difficulty_configurable(timestamps_local, cumulative_difficulties, target_seconds, REDEF_DIFFICULTY_WINDOW, REDEF_DIFFICULTY_CUT_OLD, REDEF_DIFFICULTY_CUT_LAST);
|
||||
currency::wide_difficulty_type dif2 = bbr_next_difficulty_configurable(timestamps_local, cumulative_difficulties, target_seconds, 200, 5, 5);
|
||||
currency::wide_difficulty_type dif3 = bbr_next_difficulty_configurable(timestamps_local, cumulative_difficulties, target_seconds, 40, 1, 1);
|
||||
return (dif3 + dif2 + dif) / 3;
|
||||
}
|
||||
|
||||
currency::wide_difficulty_type bbr_next_difficulty2(std::vector<uint64_t>& timestamps, std::vector<currency::wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
{
|
||||
return bbr_next_difficulty_configurable(timestamps, cumulative_difficulties, target_seconds, NEW_DIFFICULTY_WINDOW, NEW_DIFFICULTY_CUT_OLD, NEW_DIFFICULTY_CUT_LAST);
|
||||
}
|
||||
|
||||
uint64_t get_next_timestamp_by_difficulty_and_hashrate(uint64_t last_timestamp, currency::wide_difficulty_type difficulty, uint64_t hashrate)
|
||||
{
|
||||
uint64_t seconds = (difficulty / hashrate).convert_to<uint64_t>();
|
||||
return last_timestamp + seconds;
|
||||
}
|
||||
|
||||
void print_blocks(const std::vector<std::vector<uint64_t>>& blocks, const std::string& res_path)
|
||||
{
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i != blocks.size(); i++)
|
||||
{
|
||||
ss << std::left << std::setw(10) << i << std::left << std::setw(15) << blocks[i][0];
|
||||
for (size_t j = 1; j != blocks[i].size()-1; j++)
|
||||
{
|
||||
ss << std::left << std::setw(15) << blocks[i][j];
|
||||
}
|
||||
ss << std::left << std::setw(20) << blocks[i][blocks[i].size() - 1] << ENDL;
|
||||
}
|
||||
file_io_utils::save_string_to_file(res_path, ss.str());
|
||||
LOG_PRINT_L0("Done, saved to file " << res_path);
|
||||
}
|
||||
|
||||
uint64_t get_hashrate_by_timestamp(const std::map<uint64_t, uint64_t> timestamp_to_hashrate, uint64_t timestamp)
|
||||
{
|
||||
auto it = timestamp_to_hashrate.lower_bound(timestamp);
|
||||
if (it == timestamp_to_hashrate.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(it->first == timestamp)
|
||||
return it->second;
|
||||
|
||||
if (it == timestamp_to_hashrate.begin())
|
||||
{
|
||||
LOG_ERROR("Internal error, lower_bound returned begin for timestamp " << timestamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (--it)->second;;
|
||||
}
|
||||
|
||||
|
||||
template<typename cb_t>
|
||||
void perform_simulation_for_function(const std::map<uint64_t, uint64_t>& timestamp_to_hashrate, uint64_t index_in_result, const std::vector<std::vector<uint64_t>>& blocks, std::vector<std::vector<uint64_t>>& result_blocks, cb_t cb)
|
||||
{
|
||||
std::vector<uint64_t> timestamps;
|
||||
std::vector<currency::wide_difficulty_type> cumul_difficulties;
|
||||
timestamps.reserve(4010);
|
||||
cumul_difficulties.reserve(4010);
|
||||
timestamps.push_back(blocks[0][0]);
|
||||
cumul_difficulties.push_back(blocks[0][1] * 120);
|
||||
currency::wide_difficulty_type curren_difficulty = 0;
|
||||
|
||||
size_t index_in_result_blocks = 0;
|
||||
while (true)
|
||||
{
|
||||
uint64_t hr = 0;
|
||||
for (size_t i = 0; i != 10; i++)
|
||||
{
|
||||
if (timestamps.size() < BBR_DIFFICULTY_WINDOW)
|
||||
{
|
||||
curren_difficulty = blocks[index_in_result_blocks][1] * 120;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<uint64_t> backward_timestamps;
|
||||
backward_timestamps.reserve(BBR_DIFFICULTY_WINDOW);
|
||||
std::copy(timestamps.rbegin(), timestamps.rbegin() + BBR_DIFFICULTY_WINDOW - 1, std::back_inserter(backward_timestamps));
|
||||
std::vector<currency::wide_difficulty_type> backward_cumul_difficulties;
|
||||
backward_cumul_difficulties.reserve(BBR_DIFFICULTY_WINDOW);
|
||||
std::copy(cumul_difficulties.rbegin(), cumul_difficulties.rbegin() + BBR_DIFFICULTY_WINDOW - 1, std::back_inserter(backward_cumul_difficulties));
|
||||
uint64_t ts = timestamps.back();
|
||||
curren_difficulty = cb(backward_timestamps, backward_cumul_difficulties, BBR_DIFFICULTY_TARGET);
|
||||
}
|
||||
cumul_difficulties.push_back(cumul_difficulties.back() + curren_difficulty);
|
||||
hr = get_hashrate_by_timestamp(timestamp_to_hashrate, timestamps.back());
|
||||
if (!hr)
|
||||
break;
|
||||
timestamps.push_back(get_next_timestamp_by_difficulty_and_hashrate(timestamps.back(), curren_difficulty, hr));
|
||||
}
|
||||
if (!hr)
|
||||
break;
|
||||
|
||||
result_blocks[index_in_result_blocks][index_in_result] = timestamps.back();
|
||||
result_blocks[index_in_result_blocks][index_in_result + 1] = curren_difficulty.convert_to<uint64_t>() / 120;
|
||||
index_in_result_blocks++;
|
||||
std::cout << index_in_result_blocks << "\r";
|
||||
}
|
||||
if (index_in_result_blocks < 410)
|
||||
{
|
||||
for (size_t k = index_in_result_blocks; k != 410; k++)
|
||||
result_blocks[k][index_in_result] = result_blocks[k-1][index_in_result];
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
void run_emulation(const std::string& path)
|
||||
|
|
@ -53,9 +266,54 @@ void run_emulation(const std::string& path)
|
|||
//0 - timestamp, 1 - difficulty/120, 2 net hashrate (h/s)
|
||||
|
||||
std::vector<std::vector<uint64_t>> blocks;
|
||||
std::vector<std::vector<uint64_t>> result_blocks;
|
||||
blocks.reserve(401);
|
||||
result_blocks.reserve(401);
|
||||
// std::vector<uint64_t> timestamps, timestamps_new;
|
||||
// std::vector<currency::wide_difficulty_type> cumul_difficulties, cumul_difficulties_new;
|
||||
// timestamps.reserve(4010);
|
||||
// cumul_difficulties.reserve(4010);
|
||||
// timestamps_new.reserve(4010);
|
||||
// cumul_difficulties_new.reserve(4010);
|
||||
|
||||
|
||||
parse_file(path, blocks, 500);
|
||||
result_blocks.resize(blocks.size() * 2);
|
||||
for (auto& b : result_blocks) {b.resize(20);}
|
||||
|
||||
std::map<uint64_t, uint64_t> timestamp_to_hashrate;
|
||||
for (uint64_t b_no = 0; b_no != blocks.size(); b_no++)
|
||||
{
|
||||
auto& b_line = blocks[b_no];
|
||||
timestamp_to_hashrate[b_line[0]] = b_line[2];
|
||||
result_blocks[b_no][0] = b_line[0];
|
||||
result_blocks[b_no][1] = b_line[2];
|
||||
}
|
||||
|
||||
uint64_t current_index = 2;
|
||||
|
||||
#define PERFORME_SIMULATION_FOR_FUNCTION(func_name, window_size, cut_old, cut_new ) \
|
||||
perform_simulation_for_function(timestamp_to_hashrate, current_index, blocks, result_blocks, \
|
||||
[&](std::vector<uint64_t>& timestamps, std::vector<currency::wide_difficulty_type>& cumulative_difficulties, size_t target_seconds) \
|
||||
{ \
|
||||
return func_name(timestamps, cumulative_difficulties, target_seconds, window_size, cut_old, cut_new); \
|
||||
}); \
|
||||
current_index+=2;
|
||||
|
||||
PERFORME_SIMULATION_FOR_FUNCTION(bbr_next_difficulty_configurable, BBR_DIFFICULTY_WINDOW, BBR_DIFFICULTY_CUT, BBR_DIFFICULTY_CUT);
|
||||
PERFORME_SIMULATION_FOR_FUNCTION(bbr_next_difficulty_configurable, 500, 60, 60);
|
||||
PERFORME_SIMULATION_FOR_FUNCTION(bbr_next_difficulty_configurable, 300, 60, 60);
|
||||
PERFORME_SIMULATION_FOR_FUNCTION(bbr_next_difficulty_composit, 720, 60, 60);
|
||||
|
||||
print_blocks(result_blocks, path + "result.txt");
|
||||
LOG_PRINT_L0("Done");
|
||||
}
|
||||
|
||||
|
||||
void run_difficulty_analysis(const std::string& path)
|
||||
{
|
||||
//hash_rate_analysis(path);
|
||||
run_emulation(path);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue