commit
f879d48df7
|
@ -48,6 +48,8 @@ message(STATUS "CMake version ${CMAKE_VERSION}")
|
|||
|
||||
project(monero)
|
||||
|
||||
include(FindCcache) # Has to be included after the project() macro, to be able to read the CXX variable.
|
||||
|
||||
enable_language(C ASM)
|
||||
|
||||
function (die msg)
|
||||
|
|
|
@ -53,8 +53,8 @@ RUN set -ex \
|
|||
ENV BOOST_ROOT /usr/local/boost_${BOOST_VERSION}
|
||||
|
||||
# OpenSSL
|
||||
ARG OPENSSL_VERSION=1.1.1b
|
||||
ARG OPENSSL_HASH=5c557b023230413dfb0756f3137a13e6d726838ccd1430888ad15bfb2b43ea4b
|
||||
ARG OPENSSL_VERSION=1.1.1g
|
||||
ARG OPENSSL_HASH=ddb04774f1e32f0c49751e21b67216ac87852ceb056b75209af2443400636d46
|
||||
RUN set -ex \
|
||||
&& curl -s -O https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz \
|
||||
&& echo "${OPENSSL_HASH} openssl-${OPENSSL_VERSION}.tar.gz" | sha256sum -c \
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
# Copyright (c) 2014-2020, The Monero Project
|
||||
#
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification, are
|
||||
# permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
# conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
# of conditions and the following disclaimer in the documentation and/or other
|
||||
# materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software without specific
|
||||
# prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
# - Try to find readline include dirs and libraries
|
||||
#
|
||||
# Automatically finds ccache build accelerator, if it's found in PATH.
|
||||
#
|
||||
# Usage of this module as follows:
|
||||
#
|
||||
# project(monero)
|
||||
# include(FindCcache) # Include AFTER the project() macro to be able to reach the CMAKE_CXX_COMPILER variable
|
||||
#
|
||||
# Properties modified by this module:
|
||||
#
|
||||
# GLOBAL PROPERTY RULE_LAUNCH_COMPILE set to ccache, when ccache found
|
||||
# GLOBAL PROPERTY RULE_LAUNCH_LINK set to ccache, when ccache found
|
||||
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
if (CCACHE_FOUND)
|
||||
set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp")
|
||||
file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }")
|
||||
execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET)
|
||||
if (${RET} EQUAL 0)
|
||||
message("found usable ccache: ${CCACHE_FOUND}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_FOUND}")
|
||||
else()
|
||||
message("found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}")
|
||||
endif()
|
||||
else()
|
||||
message("ccache NOT found!")
|
||||
endif()
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package=openssl
|
||||
$(package)_version=1.0.2r
|
||||
$(package)_download_path=https://www.openssl.org/source
|
||||
$(package)_download_path=https://ftp.openssl.org/source/old/1.0.2
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=ae51d08bba8a83958e894946f15303ff894d75c2b8bbd44a852b64e3fe11d0d6
|
||||
$(package)_patches=fix_arflags.patch
|
||||
|
|
|
@ -42,7 +42,12 @@ namespace epee
|
|||
|
||||
struct release_byte_slice
|
||||
{
|
||||
void operator()(byte_slice_data*) const noexcept;
|
||||
//! For use with `zmq_message_init_data`, use second arg for buffer pointer.
|
||||
static void call(void*, void* ptr) noexcept;
|
||||
void operator()(byte_slice_data* ptr) const noexcept
|
||||
{
|
||||
call(nullptr, ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/*! Inspired by slices in golang. Storage is thread-safe reference counted,
|
||||
|
@ -140,6 +145,9 @@ namespace epee
|
|||
\throw std::out_of_range If `size() < end`.
|
||||
\return Slice starting at `data() + begin` of size `end - begin`. */
|
||||
byte_slice get_slice(std::size_t begin, std::size_t end) const;
|
||||
|
||||
//! \post `empty()` \return Ownership of ref-counted buffer.
|
||||
std::unique_ptr<byte_slice_data, release_byte_slice> take_buffer() noexcept;
|
||||
};
|
||||
} // epee
|
||||
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Andrey N. Sabelnikov nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include "http_auth.h"
|
||||
#include "net/net_ssl.h"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
inline const char* get_hex_vals()
|
||||
{
|
||||
static constexpr const char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
return hexVals;
|
||||
}
|
||||
|
||||
inline const char* get_unsave_chars()
|
||||
{
|
||||
//static constexpr char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
|
||||
static constexpr const char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
|
||||
return unsave_chars;
|
||||
}
|
||||
|
||||
bool is_unsafe(unsigned char compare_char);
|
||||
std::string dec_to_hex(char num, int radix);
|
||||
int get_index(const char *s, char c);
|
||||
std::string hex_to_dec_2bytes(const char *s);
|
||||
std::string convert(char val);
|
||||
std::string conver_to_url_format(const std::string& uri);
|
||||
std::string convert_from_url_format(const std::string& uri);
|
||||
std::string convert_to_url_format_force_all(const std::string& uri);
|
||||
|
||||
namespace http
|
||||
{
|
||||
class abstract_http_client
|
||||
{
|
||||
public:
|
||||
abstract_http_client() {}
|
||||
virtual ~abstract_http_client() {}
|
||||
bool set_server(const std::string& address, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
|
||||
virtual void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect) = 0;
|
||||
virtual void set_auto_connect(bool auto_connect) = 0;
|
||||
virtual bool connect(std::chrono::milliseconds timeout) = 0;
|
||||
virtual bool disconnect() = 0;
|
||||
virtual bool is_connected(bool *ssl = NULL) = 0;
|
||||
virtual bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0;
|
||||
virtual bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0;
|
||||
virtual bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) = 0;
|
||||
virtual uint64_t get_bytes_sent() const = 0;
|
||||
virtual uint64_t get_bytes_received() const = 0;
|
||||
};
|
||||
|
||||
class http_client_factory
|
||||
{
|
||||
public:
|
||||
virtual ~http_client_factory() {}
|
||||
virtual std::unique_ptr<abstract_http_client> create() = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,6 +33,7 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "memwipe.h"
|
||||
#include "string_tools.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
|
@ -200,6 +201,11 @@ namespace net_utils
|
|||
this->~http_response_info();
|
||||
new(this) http_response_info();
|
||||
}
|
||||
|
||||
void wipe()
|
||||
{
|
||||
memwipe(&m_body[0], m_body.size());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
|
||||
#include "string_tools.h"
|
||||
#include "reg_exp_definer.h"
|
||||
#include "abstract_http_client.h"
|
||||
#include "http_base.h"
|
||||
#include "http_auth.h"
|
||||
#include "to_nonconst_iterator.h"
|
||||
|
@ -105,140 +106,11 @@ namespace net_utils
|
|||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
static inline const char* get_hex_vals()
|
||||
{
|
||||
static const char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
return hexVals;
|
||||
}
|
||||
|
||||
static inline const char* get_unsave_chars()
|
||||
{
|
||||
//static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&";
|
||||
static const char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&";
|
||||
return unsave_chars;
|
||||
}
|
||||
|
||||
static inline bool is_unsafe(unsigned char compare_char)
|
||||
{
|
||||
if(compare_char <= 32 || compare_char >= 123)
|
||||
return true;
|
||||
|
||||
const char* punsave = get_unsave_chars();
|
||||
|
||||
for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++)
|
||||
if(compare_char == punsave[ichar_pos])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline
|
||||
std::string dec_to_hex(char num, int radix)
|
||||
{
|
||||
int temp=0;
|
||||
std::string csTmp;
|
||||
int num_char;
|
||||
|
||||
num_char = (int) num;
|
||||
if (num_char < 0)
|
||||
num_char = 256 + num_char;
|
||||
|
||||
while (num_char >= radix)
|
||||
{
|
||||
temp = num_char % radix;
|
||||
num_char = (int)floor((float)num_char / (float)radix);
|
||||
csTmp = get_hex_vals()[temp];
|
||||
}
|
||||
|
||||
csTmp += get_hex_vals()[num_char];
|
||||
|
||||
if(csTmp.size() < 2)
|
||||
{
|
||||
csTmp += '0';
|
||||
}
|
||||
|
||||
std::reverse(csTmp.begin(), csTmp.end());
|
||||
//_mbsrev((unsigned char*)csTmp.data());
|
||||
|
||||
return csTmp;
|
||||
}
|
||||
static inline int get_index(const char *s, char c) { const char *ptr = (const char*)memchr(s, c, 16); return ptr ? ptr-s : -1; }
|
||||
static inline
|
||||
std::string hex_to_dec_2bytes(const char *s)
|
||||
{
|
||||
const char *hex = get_hex_vals();
|
||||
int i0 = get_index(hex, toupper(s[0]));
|
||||
int i1 = get_index(hex, toupper(s[1]));
|
||||
if (i0 < 0 || i1 < 0)
|
||||
return std::string("%") + std::string(1, s[0]) + std::string(1, s[1]);
|
||||
return std::string(1, i0 * 16 | i1);
|
||||
}
|
||||
|
||||
static inline std::string convert(char val)
|
||||
{
|
||||
std::string csRet;
|
||||
csRet += "%";
|
||||
csRet += dec_to_hex(val, 16);
|
||||
return csRet;
|
||||
}
|
||||
static inline std::string conver_to_url_format(const std::string& uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
if(is_unsafe(uri[i]))
|
||||
result += convert(uri[i]);
|
||||
else
|
||||
result += uri[i];
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
static inline std::string convert_from_url_format(const std::string& uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
if(uri[i] == '%' && i + 2 < uri.size())
|
||||
{
|
||||
result += hex_to_dec_2bytes(uri.c_str() + i + 1);
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
result += uri[i];
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline std::string convert_to_url_format_force_all(const std::string& uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
result += convert(uri[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace http
|
||||
{
|
||||
|
||||
template<typename net_client_type>
|
||||
class http_simple_client_template: public i_target_handler
|
||||
class http_simple_client_template : public i_target_handler, public abstract_http_client
|
||||
{
|
||||
private:
|
||||
enum reciev_machine_state
|
||||
|
@ -279,7 +151,7 @@ namespace net_utils
|
|||
|
||||
public:
|
||||
explicit http_simple_client_template()
|
||||
: i_target_handler()
|
||||
: i_target_handler(), abstract_http_client()
|
||||
, m_net_client()
|
||||
, m_host_buff()
|
||||
, m_port()
|
||||
|
@ -299,16 +171,9 @@ namespace net_utils
|
|||
const std::string &get_host() const { return m_host_buff; };
|
||||
const std::string &get_port() const { return m_port; };
|
||||
|
||||
bool set_server(const std::string& address, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
http::url_content parsed{};
|
||||
const bool r = parse_url(address, parsed);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
|
||||
return true;
|
||||
}
|
||||
using abstract_http_client::set_server;
|
||||
|
||||
void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect)
|
||||
void set_server(std::string host, std::string port, boost::optional<login> user, ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect) override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
disconnect();
|
||||
|
@ -318,7 +183,7 @@ namespace net_utils
|
|||
m_net_client.set_ssl(std::move(ssl_options));
|
||||
}
|
||||
|
||||
void set_auto_connect(bool auto_connect)
|
||||
void set_auto_connect(bool auto_connect) override
|
||||
{
|
||||
m_auto_connect = auto_connect;
|
||||
}
|
||||
|
@ -330,25 +195,25 @@ namespace net_utils
|
|||
m_net_client.set_connector(std::move(connector));
|
||||
}
|
||||
|
||||
bool connect(std::chrono::milliseconds timeout)
|
||||
bool connect(std::chrono::milliseconds timeout) override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return m_net_client.connect(m_host_buff, m_port, timeout);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool disconnect()
|
||||
bool disconnect() override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return m_net_client.disconnect();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
bool is_connected(bool *ssl = NULL)
|
||||
bool is_connected(bool *ssl = NULL) override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return m_net_client.is_connected(ssl);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
virtual bool handle_target_data(std::string& piece_of_transfer)
|
||||
virtual bool handle_target_data(std::string& piece_of_transfer) override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
m_response_info.m_body += piece_of_transfer;
|
||||
|
@ -361,15 +226,14 @@ namespace net_utils
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
inline
|
||||
bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
inline bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return invoke(uri, "GET", body, timeout, ppresponse_info, additional_params);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
if(!is_connected())
|
||||
|
@ -442,7 +306,7 @@ namespace net_utils
|
|||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list())
|
||||
inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) override
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_lock);
|
||||
return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params);
|
||||
|
@ -456,16 +320,21 @@ namespace net_utils
|
|||
return handle_reciev(timeout);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
uint64_t get_bytes_sent() const
|
||||
uint64_t get_bytes_sent() const override
|
||||
{
|
||||
return m_net_client.get_bytes_sent();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
uint64_t get_bytes_received() const
|
||||
uint64_t get_bytes_received() const override
|
||||
{
|
||||
return m_net_client.get_bytes_received();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
void wipe_response()
|
||||
{
|
||||
m_response_info.wipe();
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
private:
|
||||
//---------------------------------------------------------------------------
|
||||
inline bool handle_reciev(std::chrono::milliseconds timeout)
|
||||
|
@ -1016,6 +885,14 @@ namespace net_utils
|
|||
}
|
||||
};
|
||||
typedef http_simple_client_template<blocked_mode_client> http_simple_client;
|
||||
|
||||
class http_simple_client_factory : public http_client_factory
|
||||
{
|
||||
public:
|
||||
std::unique_ptr<abstract_http_client> create() override {
|
||||
return std::unique_ptr<epee::net_utils::http::abstract_http_client>(new epee::net_utils::http::http_simple_client());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace epee
|
|||
namespace net_utils
|
||||
{
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "GET")
|
||||
bool invoke_http_json(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST")
|
||||
{
|
||||
std::string req_param;
|
||||
if(!serialization::store_t_to_json(out_struct, req_param))
|
||||
|
@ -72,7 +72,7 @@ namespace epee
|
|||
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "GET")
|
||||
bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref method = "POST")
|
||||
{
|
||||
std::string req_param;
|
||||
if(!serialization::store_t_to_binary(out_struct, req_param))
|
||||
|
@ -101,7 +101,7 @@ namespace epee
|
|||
}
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, epee::json_rpc::error &error_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, epee::json_rpc::error &error_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
|
||||
{
|
||||
epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t);
|
||||
req_t.jsonrpc = "2.0";
|
||||
|
@ -125,14 +125,14 @@ namespace epee
|
|||
}
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
|
||||
{
|
||||
epee::json_rpc::error error_struct;
|
||||
return invoke_http_json_rpc(uri, method_name, out_struct, result_struct, error_struct, transport, timeout, http_method, req_id);
|
||||
}
|
||||
|
||||
template<class t_command, class t_transport>
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
|
||||
bool invoke_http_json_rpc(const boost::string_ref uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
|
||||
{
|
||||
return invoke_http_json_rpc(uri, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id);
|
||||
}
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace epee
|
|||
};
|
||||
|
||||
|
||||
#define CRITICAL_REGION_LOCAL(x) {boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep()));} epee::critical_region_t<decltype(x)> critical_region_var(x)
|
||||
#define CRITICAL_REGION_LOCAL(x) {} epee::critical_region_t<decltype(x)> critical_region_var(x)
|
||||
#define CRITICAL_REGION_BEGIN(x) { boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep())); epee::critical_region_t<decltype(x)> critical_region_var(x)
|
||||
#define CRITICAL_REGION_LOCAL1(x) {boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep()));} epee::critical_region_t<decltype(x)> critical_region_var1(x)
|
||||
#define CRITICAL_REGION_BEGIN1(x) { boost::this_thread::sleep_for(boost::chrono::milliseconds(epee::debug::g_test_dbg_lock_sleep())); epee::critical_region_t<decltype(x)> critical_region_var1(x)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
add_library(epee STATIC byte_slice.cpp hex.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp
|
||||
add_library(epee STATIC byte_slice.cpp hex.cpp abstract_http_client.cpp http_auth.cpp mlog.cpp net_helper.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp
|
||||
levin_base.cpp memwipe.c connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp net_ssl.cpp
|
||||
int-util.cpp)
|
||||
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
#include "net/abstract_http_client.h"
|
||||
#include "net/http_base.h"
|
||||
#include "net/net_parse_helpers.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.http"
|
||||
|
||||
namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool is_unsafe(unsigned char compare_char)
|
||||
{
|
||||
if(compare_char <= 32 || compare_char >= 123)
|
||||
return true;
|
||||
|
||||
const char* punsave = get_unsave_chars();
|
||||
|
||||
for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++)
|
||||
if(compare_char == punsave[ichar_pos])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string dec_to_hex(char num, int radix)
|
||||
{
|
||||
int temp=0;
|
||||
std::string csTmp;
|
||||
int num_char;
|
||||
|
||||
num_char = (int) num;
|
||||
if (num_char < 0)
|
||||
num_char = 256 + num_char;
|
||||
|
||||
while (num_char >= radix)
|
||||
{
|
||||
temp = num_char % radix;
|
||||
num_char = (int)floor((float)num_char / (float)radix);
|
||||
csTmp = get_hex_vals()[temp];
|
||||
}
|
||||
|
||||
csTmp += get_hex_vals()[num_char];
|
||||
|
||||
if(csTmp.size() < 2)
|
||||
{
|
||||
csTmp += '0';
|
||||
}
|
||||
|
||||
std::reverse(csTmp.begin(), csTmp.end());
|
||||
//_mbsrev((unsigned char*)csTmp.data());
|
||||
|
||||
return csTmp;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
int get_index(const char *s, char c)
|
||||
{
|
||||
const char *ptr = (const char*)memchr(s, c, 16);
|
||||
return ptr ? ptr-s : -1;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string hex_to_dec_2bytes(const char *s)
|
||||
{
|
||||
const char *hex = get_hex_vals();
|
||||
int i0 = get_index(hex, toupper(s[0]));
|
||||
int i1 = get_index(hex, toupper(s[1]));
|
||||
if (i0 < 0 || i1 < 0)
|
||||
return std::string("%") + std::string(1, s[0]) + std::string(1, s[1]);
|
||||
return std::string(1, i0 * 16 | i1);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string convert(char val)
|
||||
{
|
||||
std::string csRet;
|
||||
csRet += "%";
|
||||
csRet += dec_to_hex(val, 16);
|
||||
return csRet;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string conver_to_url_format(const std::string& uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
if(is_unsafe(uri[i]))
|
||||
result += convert(uri[i]);
|
||||
else
|
||||
result += uri[i];
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string convert_from_url_format(const std::string& uri)
|
||||
{
|
||||
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
if(uri[i] == '%' && i + 2 < uri.size())
|
||||
{
|
||||
result += hex_to_dec_2bytes(uri.c_str() + i + 1);
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
result += uri[i];
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string convert_to_url_format_force_all(const std::string& uri)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
for(size_t i = 0; i!= uri.size(); i++)
|
||||
{
|
||||
result += convert(uri[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace http
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool epee::net_utils::http::abstract_http_client::set_server(const std::string& address, boost::optional<login> user, ssl_options_t ssl_options)
|
||||
{
|
||||
http::url_content parsed{};
|
||||
const bool r = parse_url(address, parsed);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,12 +49,16 @@ namespace epee
|
|||
std::atomic<std::size_t> ref_count;
|
||||
};
|
||||
|
||||
void release_byte_slice::operator()(byte_slice_data* ptr) const noexcept
|
||||
void release_byte_slice::call(void*, void* ptr) noexcept
|
||||
{
|
||||
if (ptr && --(ptr->ref_count) == 0)
|
||||
if (ptr)
|
||||
{
|
||||
ptr->~byte_slice_data();
|
||||
free(ptr);
|
||||
byte_slice_data* self = static_cast<byte_slice_data*>(ptr);
|
||||
if (--(self->ref_count) == 0)
|
||||
{
|
||||
self->~byte_slice_data();
|
||||
free(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,4 +210,11 @@ namespace epee
|
|||
return {};
|
||||
return {storage_.get(), {portion_.begin() + begin, end - begin}};
|
||||
}
|
||||
|
||||
std::unique_ptr<byte_slice_data, release_byte_slice> byte_slice::take_buffer() noexcept
|
||||
{
|
||||
std::unique_ptr<byte_slice_data, release_byte_slice> out{std::move(storage_)};
|
||||
portion_ = nullptr;
|
||||
return out;
|
||||
}
|
||||
} // epee
|
||||
|
|
|
@ -141,7 +141,7 @@ namespace epee
|
|||
result.reserve(count / 2);
|
||||
|
||||
// the data to work with (std::string is always null-terminated)
|
||||
auto data = src.data();
|
||||
auto data = src.begin();
|
||||
|
||||
// convert a single hex character to an unsigned integer
|
||||
auto char_to_int = [](const char *input) {
|
||||
|
@ -167,9 +167,9 @@ namespace epee
|
|||
};
|
||||
|
||||
// keep going until we reach the end
|
||||
while (data[0] != '\0') {
|
||||
while (data != src.end()) {
|
||||
// skip unwanted characters
|
||||
if (!include(data[0])) {
|
||||
if (!include(*data)) {
|
||||
++data;
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 31a0073c62738827b48d725facd3766879429124
|
||||
Subproject commit bff7fdfe436c727982cc553bdfb29a9021b423b0
|
|
@ -66,7 +66,6 @@ using namespace epee;
|
|||
#include "util.h"
|
||||
#include "stack_trace.h"
|
||||
#include "memwipe.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "net/http_client.h" // epee::net_utils::...
|
||||
#include "readline_buffer.h"
|
||||
|
||||
|
@ -1074,16 +1073,33 @@ std::string get_nix_version_display_string()
|
|||
{
|
||||
if (seconds < 60)
|
||||
return std::to_string(seconds) + " seconds";
|
||||
std::stringstream ss;
|
||||
ss << std::fixed << std::setprecision(1);
|
||||
if (seconds < 3600)
|
||||
return std::to_string((uint64_t)(seconds / 60)) + " minutes";
|
||||
{
|
||||
ss << seconds / 60.f;
|
||||
return ss.str() + " minutes";
|
||||
}
|
||||
if (seconds < 3600 * 24)
|
||||
return std::to_string((uint64_t)(seconds / 3600)) + " hours";
|
||||
if (seconds < 3600 * 24 * 30.5)
|
||||
return std::to_string((uint64_t)(seconds / (3600 * 24))) + " days";
|
||||
if (seconds < 3600 * 24 * 365.25)
|
||||
return std::to_string((uint64_t)(seconds / (3600 * 24 * 30.5))) + " months";
|
||||
if (seconds < 3600 * 24 * 365.25 * 100)
|
||||
return std::to_string((uint64_t)(seconds / (3600 * 24 * 30.5 * 365.25))) + " years";
|
||||
{
|
||||
ss << seconds / 3600.f;
|
||||
return ss.str() + " hours";
|
||||
}
|
||||
if (seconds < 3600 * 24 * 30.5f)
|
||||
{
|
||||
ss << seconds / (3600 * 24.f);
|
||||
return ss.str() + " days";
|
||||
}
|
||||
if (seconds < 3600 * 24 * 365.25f)
|
||||
{
|
||||
ss << seconds / (3600 * 24 * 30.5f);
|
||||
return ss.str() + " months";
|
||||
}
|
||||
if (seconds < 3600 * 24 * 365.25f * 100)
|
||||
{
|
||||
ss << seconds / (3600 * 24 * 365.25f);
|
||||
return ss.str() + " years";
|
||||
}
|
||||
return "a long time";
|
||||
}
|
||||
|
||||
|
@ -1279,6 +1295,86 @@ std::string get_nix_version_display_string()
|
|||
return lines;
|
||||
}
|
||||
|
||||
// Calculate a "sync weight" over ranges of blocks in the blockchain, suitable for
|
||||
// calculating sync time estimates
|
||||
uint64_t cumulative_block_sync_weight(cryptonote::network_type nettype, uint64_t start_block, uint64_t num_blocks)
|
||||
{
|
||||
if (nettype != cryptonote::MAINNET)
|
||||
{
|
||||
// No detailed data available except for Mainnet: Give back the number of blocks
|
||||
// as a very simple and non-varying block sync weight for ranges of Testnet and
|
||||
// Stagenet blocks
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
// The following is a table of average blocks sizes in bytes over the Monero mainnet
|
||||
// blockchain, where the block size is averaged over ranges of 10,000 blocks
|
||||
// (about 2 weeks worth of blocks each).
|
||||
// The first array entry of 442 thus means "The average byte size of the blocks
|
||||
// 0 .. 9,999 is 442". The info "block_size" from the "get_block_header_by_height"
|
||||
// RPC call was used for calculating this. This table (and the whole mechanism
|
||||
// of calculating a "sync weight") is most important when estimating times for
|
||||
// syncing from scratch. Without it the fast progress through the (in comparison)
|
||||
// rather small blocks in the early blockchain) would lead to vastly underestimated
|
||||
// total sync times.
|
||||
// It's no big problem for estimates that this table will, over time, and if not
|
||||
// updated, miss larger and larger parts at the top of the blockchain, as long
|
||||
// as block size averages there do not differ wildly.
|
||||
// Without time-consuming tests it's hard to say how much the estimates would
|
||||
// improve if one would not only take block sizes into account, but also varying
|
||||
// verification times i.e. the different CPU effort needed for the different
|
||||
// transaction types (pre / post RingCT, pre / post Bulletproofs).
|
||||
// Testnet and Stagenet are neglected here because of their much smaller
|
||||
// importance.
|
||||
static const uint32_t average_block_sizes[] =
|
||||
{
|
||||
442, 1211, 1445, 1763, 2272, 8217, 5603, 9999, 16358, 10805, 5290, 4362,
|
||||
4325, 5584, 4515, 5008, 4789, 5196, 7660, 3829, 6034, 2925, 3762, 2545,
|
||||
2437, 2553, 2167, 2761, 2015, 1969, 2350, 1731, 2367, 2078, 2026, 3518,
|
||||
2214, 1908, 1780, 1640, 1976, 1647, 1921, 1716, 1895, 2150, 2419, 2451,
|
||||
2147, 2327, 2251, 1644, 1750, 1481, 1570, 1524, 1562, 1668, 1386, 1494,
|
||||
1637, 1880, 1431, 1472, 1637, 1363, 1762, 1597, 1999, 1564, 1341, 1388,
|
||||
1530, 1476, 1617, 1488, 1368, 1906, 1403, 1695, 1535, 1598, 1318, 1234,
|
||||
1358, 1406, 1698, 1554, 1591, 1758, 1426, 2389, 1946, 1533, 1308, 2701,
|
||||
1525, 1653, 3580, 1889, 2913, 8164, 5154, 3762, 3356, 4360, 3589, 4844,
|
||||
4232, 3781, 3882, 5924, 10790, 7185, 7442, 8214, 8509, 7484, 6939, 7391,
|
||||
8210, 15572, 39680, 44810, 53873, 54639, 68227, 63428, 62386, 68504,
|
||||
83073, 103858, 117573, 98089, 96793, 102337, 94714, 129568, 251584,
|
||||
132026, 94579, 94516, 95722, 106495, 121824, 153983, 162338, 136608,
|
||||
137104, 109872, 91114, 84757, 96339, 74251, 94314, 143216, 155837,
|
||||
129968, 120201, 109913, 101588, 97332, 104611, 95310, 93419, 113345,
|
||||
100743, 92152, 57565, 22533, 37564, 21823, 19980, 18277, 18402, 14344,
|
||||
12142, 15842, 13677, 17631, 18294, 22270, 41422, 39296, 36688, 33512,
|
||||
33831, 27582, 22276, 27516, 27317, 25505, 24426, 20566, 23045, 26766,
|
||||
28185, 26169, 27011,
|
||||
28642 // Blocks 1,990,000 to 1,999,999 in December 2019
|
||||
};
|
||||
const uint64_t block_range_size = 10000;
|
||||
|
||||
uint64_t num_block_sizes = sizeof(average_block_sizes) / sizeof(average_block_sizes[0]);
|
||||
uint64_t weight = 0;
|
||||
uint64_t table_index = start_block / block_range_size;
|
||||
for (;;) {
|
||||
if (num_blocks == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (table_index >= num_block_sizes)
|
||||
{
|
||||
// Take all blocks beyond our table as having the size of the blocks
|
||||
// in the last table entry i.e. in the most recent known block range
|
||||
weight += num_blocks * average_block_sizes[num_block_sizes - 1];
|
||||
break;
|
||||
}
|
||||
uint64_t portion_size = std::min(num_blocks, block_range_size - start_block % block_range_size);
|
||||
weight += portion_size * average_block_sizes[table_index];
|
||||
table_index++;
|
||||
num_blocks -= portion_size;
|
||||
start_block += portion_size;
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, size_t>> split_string_by_width(const std::string &s, size_t columns)
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#endif
|
||||
|
||||
#include "crypto/hash.h"
|
||||
#include "cryptonote_config.h"
|
||||
|
||||
/*! \brief Various Tools
|
||||
*
|
||||
|
@ -252,4 +253,6 @@ namespace tools
|
|||
void clear_screen();
|
||||
|
||||
std::vector<std::pair<std::string, size_t>> split_string_by_width(const std::string &s, size_t columns);
|
||||
|
||||
uint64_t cumulative_block_sync_weight(cryptonote::network_type nettype, uint64_t start_block, uint64_t num_blocks);
|
||||
}
|
||||
|
|
|
@ -125,6 +125,20 @@ namespace cryptonote
|
|||
|
||||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h, hw::device &hwdev)
|
||||
{
|
||||
hwdev.get_transaction_prefix_hash(tx,h);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx, hw::device &hwdev)
|
||||
{
|
||||
crypto::hash h = null_hash;
|
||||
get_transaction_prefix_hash(tx, h, hwdev);
|
||||
return h;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
|
||||
{
|
||||
|
|
|
@ -48,6 +48,8 @@ namespace epee
|
|||
namespace cryptonote
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h, hw::device &hwdev);
|
||||
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx, hw::device &hwdev);
|
||||
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_prefix_from_blob(const blobdata& tx_blob, transaction_prefix& tx);
|
||||
|
|
|
@ -428,9 +428,9 @@ namespace cryptonote
|
|||
return m_blockchain_storage.get_split_transactions_blobs(txs_ids, txs, missed_txs);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_txpool_backlog(std::vector<tx_backlog_entry>& backlog) const
|
||||
bool core::get_txpool_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive_txes) const
|
||||
{
|
||||
m_mempool.get_transaction_backlog(backlog);
|
||||
m_mempool.get_transaction_backlog(backlog, include_sensitive_txes);
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
@ -1584,9 +1584,9 @@ namespace cryptonote
|
|||
return m_blockchain_storage.get_db().get_block_cumulative_difficulty(height);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
size_t core::get_pool_transactions_count() const
|
||||
size_t core::get_pool_transactions_count(bool include_sensitive_txes) const
|
||||
{
|
||||
return m_mempool.get_transactions_count();
|
||||
return m_mempool.get_transactions_count(include_sensitive_txes);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::have_block(const crypto::hash& id) const
|
||||
|
|
|
@ -469,10 +469,11 @@ namespace cryptonote
|
|||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_txpool_backlog
|
||||
* @param include_sensitive_txes include private transactions
|
||||
*
|
||||
* @note see tx_memory_pool::get_txpool_backlog
|
||||
*/
|
||||
bool get_txpool_backlog(std::vector<tx_backlog_entry>& backlog) const;
|
||||
bool get_txpool_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive_txes = false) const;
|
||||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_transactions
|
||||
|
@ -514,10 +515,11 @@ namespace cryptonote
|
|||
|
||||
/**
|
||||
* @copydoc tx_memory_pool::get_transactions_count
|
||||
* @param include_sensitive_txes include private transactions
|
||||
*
|
||||
* @note see tx_memory_pool::get_transactions_count
|
||||
*/
|
||||
size_t get_pool_transactions_count() const;
|
||||
size_t get_pool_transactions_count(bool include_sensitive_txes = false) const;
|
||||
|
||||
/**
|
||||
* @copydoc Blockchain::get_total_transactions
|
||||
|
|
|
@ -590,7 +590,7 @@ namespace cryptonote
|
|||
tx.vout[i].amount = 0;
|
||||
|
||||
crypto::hash tx_prefix_hash;
|
||||
get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||
get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev);
|
||||
rct::ctkeyV outSk;
|
||||
if (rct_config.range_proof_type != rct::RangeProofPaddedBulletproof && use_simple_rct)
|
||||
tx.rct_signatures = rct::genRctSimple_old(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, rct_config, hwdev);
|
||||
|
|
|
@ -210,7 +210,7 @@ namespace cryptonote
|
|||
// TODO: Investigate why not?
|
||||
if(!kept_by_block)
|
||||
{
|
||||
if(have_tx_keyimges_as_spent(tx))
|
||||
if(have_tx_keyimges_as_spent(tx, id))
|
||||
{
|
||||
mark_double_spend(tx);
|
||||
LOG_PRINT_L1("Transaction with id= "<< id << " used already spent key images");
|
||||
|
@ -253,7 +253,7 @@ namespace cryptonote
|
|||
meta.last_relayed_time = time(NULL);
|
||||
meta.relayed = relayed;
|
||||
meta.set_relay_method(tx_relay);
|
||||
meta.double_spend_seen = have_tx_keyimges_as_spent(tx);
|
||||
meta.double_spend_seen = have_tx_keyimges_as_spent(tx, id);
|
||||
meta.pruned = tx.pruned;
|
||||
meta.bf_padding = 0;
|
||||
memset(meta.padding, 0, sizeof(meta.padding));
|
||||
|
@ -615,8 +615,8 @@ namespace cryptonote
|
|||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
|
||||
m_blockchain.for_all_txpool_txes([this, &hashes, &txes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata*) {
|
||||
const auto relay_method = meta.get_relay_method();
|
||||
if (relay_method != relay_method::block && relay_method != relay_method::fluff)
|
||||
const auto tx_relay_method = meta.get_relay_method();
|
||||
if (tx_relay_method != relay_method::block && tx_relay_method != relay_method::fluff)
|
||||
return true;
|
||||
const auto i = std::find(hashes.begin(), hashes.end(), txid);
|
||||
if (i == hashes.end())
|
||||
|
@ -1098,30 +1098,32 @@ namespace cryptonote
|
|||
return m_blockchain.get_db().txpool_has_tx(id, tx_category);
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx) const
|
||||
bool tx_memory_pool::have_tx_keyimges_as_spent(const transaction& tx, const crypto::hash& txid) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
for(const auto& in: tx.vin)
|
||||
{
|
||||
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail
|
||||
if(have_tx_keyimg_as_spent(tokey_in.k_image))
|
||||
if(have_tx_keyimg_as_spent(tokey_in.k_image, txid))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const
|
||||
bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im, const crypto::hash& txid) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
bool spent = false;
|
||||
const auto found = m_spent_key_images.find(key_im);
|
||||
if (found != m_spent_key_images.end())
|
||||
if (found != m_spent_key_images.end() && !found->second.empty())
|
||||
{
|
||||
for (const crypto::hash& tx_hash : found->second)
|
||||
spent |= m_blockchain.txpool_tx_matches_category(tx_hash, relay_category::broadcasted);
|
||||
// If another tx is using the key image, always return as spent.
|
||||
// See `insert_key_images`.
|
||||
if (1 < found->second.size() || *(found->second.cbegin()) != txid)
|
||||
return true;
|
||||
return m_blockchain.txpool_tx_matches_category(txid, relay_category::broadcasted);
|
||||
}
|
||||
return spent;
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
void tx_memory_pool::lock() const
|
||||
|
|
|
@ -470,10 +470,11 @@ namespace cryptonote
|
|||
* @brief check if a transaction in the pool has a given spent key image
|
||||
*
|
||||
* @param key_im the spent key image to look for
|
||||
* @param txid hash of the new transaction where `key_im` was seen.
|
||||
*
|
||||
* @return true if the spent key image is present, otherwise false
|
||||
*/
|
||||
bool have_tx_keyimg_as_spent(const crypto::key_image& key_im) const;
|
||||
bool have_tx_keyimg_as_spent(const crypto::key_image& key_im, const crypto::hash& txid) const;
|
||||
|
||||
/**
|
||||
* @brief check if any spent key image in a transaction is in the pool
|
||||
|
@ -484,10 +485,11 @@ namespace cryptonote
|
|||
* @note see tx_pool::have_tx_keyimg_as_spent
|
||||
*
|
||||
* @param tx the transaction to check spent key images of
|
||||
* @param txid hash of `tx`.
|
||||
*
|
||||
* @return true if any spent key images are present in the pool, otherwise false
|
||||
*/
|
||||
bool have_tx_keyimges_as_spent(const transaction& tx) const;
|
||||
bool have_tx_keyimges_as_spent(const transaction& tx, const crypto::hash& txid) const;
|
||||
|
||||
/**
|
||||
* @brief forget a transaction's spent key images
|
||||
|
|
|
@ -170,6 +170,14 @@ namespace cryptonote
|
|||
size_t m_block_download_max_size;
|
||||
bool m_sync_pruned_blocks;
|
||||
|
||||
// Values for sync time estimates
|
||||
boost::posix_time::ptime m_sync_start_time;
|
||||
boost::posix_time::ptime m_period_start_time;
|
||||
uint64_t m_sync_start_height;
|
||||
uint64_t m_period_start_height;
|
||||
uint64_t get_estimated_remaining_sync_seconds(uint64_t current_blockchain_height, uint64_t target_blockchain_height);
|
||||
std::string get_periodic_sync_estimate(uint64_t current_blockchain_height, uint64_t target_blockchain_height);
|
||||
|
||||
boost::mutex m_buffer_mutex;
|
||||
double get_avg_block_size();
|
||||
boost::circular_buffer<size_t> m_avg_buffer = boost::circular_buffer<size_t>(10);
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "profile_tools.h"
|
||||
#include "net/network_throttle-detail.hpp"
|
||||
#include "common/pruning.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.cn"
|
||||
|
@ -362,7 +363,7 @@ namespace cryptonote
|
|||
uint64_t last_block_v1 = m_core.get_nettype() == TESTNET ? 0 : m_core.get_nettype() == MAINNET ? 0 : (uint64_t)-1;
|
||||
uint64_t diff_v2 = max_block_height > last_block_v1 ? std::min(abs_diff, max_block_height - last_block_v1) : 0;
|
||||
MCLOG(is_inital ? el::Level::Info : el::Level::Debug, "global", el::Color::Yellow, context << "Sync data returned a new top block candidate: " << m_core.get_current_blockchain_height() << " -> " << hshd.current_height
|
||||
<< " [Your node is " << abs_diff << " blocks (" << ((abs_diff - diff_v2) / (24 * 60 * 60 / DIFFICULTY_TARGET_V1)) + (diff_v2 / (24 * 60 * 60 / DIFFICULTY_TARGET_V2)) << " days) "
|
||||
<< " [Your node is " << abs_diff << " blocks (" << tools::get_human_readable_timespan((abs_diff - diff_v2) * DIFFICULTY_TARGET_V1 + diff_v2 * DIFFICULTY_TARGET_V2) << ") "
|
||||
<< (0 <= diff ? std::string("behind") : std::string("ahead"))
|
||||
<< "] " << ENDL << "SYNCHRONIZATION started");
|
||||
if (hshd.current_height >= m_core.get_current_blockchain_height() + 5) // don't switch to unsafe mode just for a few blocks
|
||||
|
@ -1212,6 +1213,55 @@ namespace cryptonote
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Get an estimate for the remaining sync time from given current to target blockchain height, in seconds
|
||||
template<class t_core>
|
||||
uint64_t t_cryptonote_protocol_handler<t_core>::get_estimated_remaining_sync_seconds(uint64_t current_blockchain_height, uint64_t target_blockchain_height)
|
||||
{
|
||||
// The average sync speed varies so much, even averaged over quite long time periods like 10 minutes,
|
||||
// that using some sliding window would be difficult to implement without often leading to bad estimates.
|
||||
// The simplest strategy - always average sync speed over the maximum available interval i.e. since sync
|
||||
// started at all (from "m_sync_start_time" and "m_sync_start_height") - gives already useful results
|
||||
// and seems to be quite robust. Some quite special cases like "Internet connection suddenly becoming
|
||||
// much faster after syncing already a long time, and staying fast" are not well supported however.
|
||||
|
||||
if (target_blockchain_height <= current_blockchain_height)
|
||||
{
|
||||
// Syncing stuck, or other special circumstance: Avoid errors, simply give back 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||
const boost::posix_time::time_duration sync_time = now - m_sync_start_time;
|
||||
cryptonote::network_type nettype = m_core.get_nettype();
|
||||
|
||||
// Don't simply use remaining number of blocks for the estimate but "sync weight" as provided by
|
||||
// "cumulative_block_sync_weight" which knows about strongly varying Monero mainnet block sizes
|
||||
uint64_t synced_weight = tools::cumulative_block_sync_weight(nettype, m_sync_start_height, current_blockchain_height - m_sync_start_height);
|
||||
float us_per_weight = (float)sync_time.total_microseconds() / (float)synced_weight;
|
||||
uint64_t remaining_weight = tools::cumulative_block_sync_weight(nettype, current_blockchain_height, target_blockchain_height - current_blockchain_height);
|
||||
float remaining_us = us_per_weight * (float)remaining_weight;
|
||||
return (uint64_t)(remaining_us / 1e6);
|
||||
}
|
||||
|
||||
// Return a textual remaining sync time estimate, or the empty string if waiting period not yet over
|
||||
template<class t_core>
|
||||
std::string t_cryptonote_protocol_handler<t_core>::get_periodic_sync_estimate(uint64_t current_blockchain_height, uint64_t target_blockchain_height)
|
||||
{
|
||||
std::string text = "";
|
||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||
boost::posix_time::time_duration period_sync_time = now - m_period_start_time;
|
||||
if (period_sync_time > boost::posix_time::minutes(2))
|
||||
{
|
||||
// Period is over, time to report another estimate
|
||||
uint64_t remaining_seconds = get_estimated_remaining_sync_seconds(current_blockchain_height, target_blockchain_height);
|
||||
text = tools::get_human_readable_timespan(remaining_seconds);
|
||||
|
||||
// Start the new period
|
||||
m_period_start_time = now;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::try_add_next_blocks(cryptonote_connection_context& context)
|
||||
{
|
||||
|
@ -1240,6 +1290,9 @@ namespace cryptonote
|
|||
if (!starting)
|
||||
m_last_add_end_time = tools::get_tick_count();
|
||||
});
|
||||
m_sync_start_time = boost::posix_time::microsec_clock::universal_time();
|
||||
m_sync_start_height = m_core.get_current_blockchain_height();
|
||||
m_period_start_time = m_sync_start_time;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
@ -1490,7 +1543,16 @@ namespace cryptonote
|
|||
if (completion_percent == 100) // never show 100% if not actually up to date
|
||||
completion_percent = 99;
|
||||
progress_message = " (" + std::to_string(completion_percent) + "%, "
|
||||
+ std::to_string(target_blockchain_height - current_blockchain_height) + " left)";
|
||||
+ std::to_string(target_blockchain_height - current_blockchain_height) + " left";
|
||||
std::string time_message = get_periodic_sync_estimate(current_blockchain_height, target_blockchain_height);
|
||||
if (!time_message.empty())
|
||||
{
|
||||
uint64_t total_blocks_to_sync = target_blockchain_height - m_sync_start_height;
|
||||
uint64_t total_blocks_synced = current_blockchain_height - m_sync_start_height;
|
||||
progress_message += ", " + std::to_string(total_blocks_synced * 100 / total_blocks_to_sync) + "% of total synced";
|
||||
progress_message += ", estimated " + time_message + " left";
|
||||
}
|
||||
progress_message += ")";
|
||||
}
|
||||
const uint32_t previous_stripe = tools::get_pruning_stripe(previous_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
||||
const uint32_t current_stripe = tools::get_pruning_stripe(current_blockchain_height, target_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
|
||||
|
@ -2228,8 +2290,26 @@ skip:
|
|||
bool t_cryptonote_protocol_handler<t_core>::on_connection_synchronized()
|
||||
{
|
||||
bool val_expected = false;
|
||||
if(!m_core.is_within_compiled_block_hash_area(m_core.get_current_blockchain_height()) && m_synchronized.compare_exchange_strong(val_expected, true))
|
||||
uint64_t current_blockchain_height = m_core.get_current_blockchain_height();
|
||||
if(!m_core.is_within_compiled_block_hash_area(current_blockchain_height) && m_synchronized.compare_exchange_strong(val_expected, true))
|
||||
{
|
||||
if ((current_blockchain_height > m_sync_start_height) && (m_sync_spans_downloaded > 0))
|
||||
{
|
||||
uint64_t synced_blocks = current_blockchain_height - m_sync_start_height;
|
||||
// Report only after syncing an "interesting" number of blocks:
|
||||
if (synced_blocks > 20)
|
||||
{
|
||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||
uint64_t synced_seconds = (now - m_sync_start_time).total_seconds();
|
||||
if (synced_seconds == 0)
|
||||
{
|
||||
synced_seconds = 1;
|
||||
}
|
||||
float blocks_per_second = (1000 * synced_blocks / synced_seconds) / 1000.0f;
|
||||
MGINFO_YELLOW("Synced " << synced_blocks << " blocks in "
|
||||
<< tools::get_human_readable_timespan(synced_seconds) << " (" << blocks_per_second << " blocks per second)");
|
||||
}
|
||||
}
|
||||
MGINFO_YELLOW(ENDL << "**********************************************************************" << ENDL
|
||||
<< "You are now synchronized with the network. You may now start wownero-wallet-cli." << ENDL
|
||||
<< ENDL
|
||||
|
|
|
@ -695,11 +695,11 @@ bool t_rpc_command_executor::print_net_stats()
|
|||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->json_rpc_request(net_stats_req, net_stats_res, "get_net_stats", fail_message.c_str()))
|
||||
if (!m_rpc_client->rpc_request(net_stats_req, net_stats_res, "/get_net_stats", fail_message.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!m_rpc_client->json_rpc_request(limit_req, limit_res, "get_limit", fail_message.c_str()))
|
||||
if (!m_rpc_client->rpc_request(limit_req, limit_res, "/get_limit", fail_message.c_str()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace cryptonote
|
|||
struct subaddress_index;
|
||||
struct tx_destination_entry;
|
||||
struct keypair;
|
||||
class transaction_prefix;
|
||||
}
|
||||
|
||||
namespace hw {
|
||||
|
@ -78,7 +79,7 @@ namespace hw {
|
|||
virtual void on_button_request(uint64_t code=0) {}
|
||||
virtual void on_button_pressed() {}
|
||||
virtual boost::optional<epee::wipeable_string> on_pin_request() { return boost::none; }
|
||||
virtual boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) { return boost::none; }
|
||||
virtual boost::optional<epee::wipeable_string> on_passphrase_request(bool & on_device) { on_device = true; return boost::none; }
|
||||
virtual void on_progress(const device_progress& event) {}
|
||||
virtual ~i_device_callback() = default;
|
||||
};
|
||||
|
@ -203,6 +204,8 @@ namespace hw {
|
|||
|
||||
virtual bool open_tx(crypto::secret_key &tx_key) = 0;
|
||||
|
||||
virtual void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) = 0;
|
||||
|
||||
virtual bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) = 0;
|
||||
bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key)
|
||||
{
|
||||
|
|
|
@ -281,6 +281,10 @@ namespace hw {
|
|||
return true;
|
||||
}
|
||||
|
||||
void device_default::get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) {
|
||||
cryptonote::get_transaction_prefix_hash(tx, h);
|
||||
}
|
||||
|
||||
bool device_default::generate_output_ephemeral_keys(const size_t tx_version,
|
||||
const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key,
|
||||
const cryptonote::tx_destination_entry &dst_entr, const boost::optional<cryptonote::account_public_address> &change_addr, const size_t output_index,
|
||||
|
|
|
@ -112,6 +112,7 @@ namespace hw {
|
|||
crypto::signature &sig) override;
|
||||
|
||||
bool open_tx(crypto::secret_key &tx_key) override;
|
||||
void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override;
|
||||
|
||||
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override;
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ namespace hw {
|
|||
|
||||
static int device_id = 0;
|
||||
|
||||
#define PROTOCOL_VERSION 2
|
||||
#define PROTOCOL_VERSION 3
|
||||
|
||||
#define INS_NONE 0x00
|
||||
#define INS_RESET 0x02
|
||||
|
@ -296,6 +296,7 @@ namespace hw {
|
|||
#define INS_BLIND 0x78
|
||||
#define INS_UNBLIND 0x7A
|
||||
#define INS_GEN_TXOUT_KEYS 0x7B
|
||||
#define INS_PREFIX_HASH 0x7D
|
||||
#define INS_VALIDATE 0x7C
|
||||
#define INS_MLSAG 0x7E
|
||||
#define INS_CLOSE_TX 0x80
|
||||
|
@ -1414,6 +1415,81 @@ namespace hw {
|
|||
return true;
|
||||
}
|
||||
|
||||
void device_ledger::get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) {
|
||||
AUTO_LOCK_CMD();
|
||||
|
||||
int pref_length = 0, pref_offset = 0, offset = 0;
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
crypto::hash h_x;
|
||||
this->controle_device->get_transaction_prefix_hash(tx,h_x);
|
||||
MDEBUG("get_transaction_prefix_hash [[IN]] h_x/1 "<<h_x);
|
||||
#endif
|
||||
|
||||
std::ostringstream s_x;
|
||||
binary_archive<true> a_x(s_x);
|
||||
CHECK_AND_ASSERT_THROW_MES(::serialization::serialize(a_x, const_cast<cryptonote::transaction_prefix&>(tx)),
|
||||
"unable to serialize transaction prefix");
|
||||
pref_length = s_x.str().size();
|
||||
//auto pref = std::make_unique<unsigned char[]>(pref_length);
|
||||
auto uprt_pref = std::unique_ptr<unsigned char[]>{ new unsigned char[pref_length] };
|
||||
unsigned char* pref = uprt_pref.get();
|
||||
memmove(pref, s_x.str().data(), pref_length);
|
||||
|
||||
offset = set_command_header_noopt(INS_PREFIX_HASH,1);
|
||||
pref_offset = 0;
|
||||
unsigned char v;
|
||||
|
||||
//version as varint
|
||||
do {
|
||||
v = pref[pref_offset];
|
||||
this->buffer_send[offset] = v;
|
||||
offset += 1;
|
||||
pref_offset += 1;
|
||||
} while (v&0x80);
|
||||
|
||||
//locktime as var int
|
||||
do {
|
||||
v = pref[pref_offset];
|
||||
this->buffer_send[offset] = v;
|
||||
offset += 1;
|
||||
pref_offset += 1;
|
||||
} while (v&0x80);
|
||||
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
this->exchange_wait_on_input();
|
||||
|
||||
//hash remains
|
||||
int cnt = 0;
|
||||
while (pref_offset < pref_length) {
|
||||
int len;
|
||||
cnt++;
|
||||
offset = set_command_header(INS_PREFIX_HASH,2,cnt);
|
||||
len = pref_length - pref_offset;
|
||||
//options
|
||||
if (len > (BUFFER_SEND_SIZE-7)) {
|
||||
len = BUFFER_SEND_SIZE-7;
|
||||
this->buffer_send[offset] = 0x80;
|
||||
} else {
|
||||
this->buffer_send[offset] = 0x00;
|
||||
}
|
||||
offset += 1;
|
||||
//send chunk
|
||||
memmove(&this->buffer_send[offset], pref+pref_offset, len);
|
||||
offset += len;
|
||||
pref_offset += len;
|
||||
this->buffer_send[4] = offset-5;
|
||||
this->length_send = offset;
|
||||
this->exchange();
|
||||
}
|
||||
memmove(h.data, &this->buffer_recv[0], 32);
|
||||
|
||||
#ifdef DEBUG_HWDEVICE
|
||||
hw::ledger::check8("prefix_hash", "h", h_x.data, h.data);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool device_ledger::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) {
|
||||
AUTO_LOCK_CMD();
|
||||
|
||||
|
|
|
@ -275,6 +275,8 @@ namespace hw {
|
|||
|
||||
bool open_tx(crypto::secret_key &tx_key) override;
|
||||
|
||||
void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) override;
|
||||
|
||||
bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) override;
|
||||
|
||||
rct::key genCommitmentMask(const rct::key &amount_key) override;
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace trezor {
|
|||
return device_trezor_base::disconnect();
|
||||
}
|
||||
|
||||
void device_trezor::device_state_reset_unsafe()
|
||||
void device_trezor::device_state_initialize_unsafe()
|
||||
{
|
||||
require_connected();
|
||||
if (m_live_refresh_in_progress)
|
||||
|
@ -117,7 +117,7 @@ namespace trezor {
|
|||
}
|
||||
|
||||
m_live_refresh_in_progress = false;
|
||||
device_trezor_base::device_state_reset_unsafe();
|
||||
device_trezor_base::device_state_initialize_unsafe();
|
||||
}
|
||||
|
||||
void device_trezor::live_refresh_thread_main()
|
||||
|
@ -221,7 +221,7 @@ namespace trezor {
|
|||
CHECK_AND_ASSERT_THROW_MES(!payment_id || !subaddress || subaddress->is_zero(), "Subaddress cannot be integrated");
|
||||
TREZOR_AUTO_LOCK_CMD();
|
||||
require_connected();
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
require_initialized();
|
||||
|
||||
auto req = std::make_shared<messages::monero::MoneroGetAddress>();
|
||||
|
@ -245,7 +245,7 @@ namespace trezor {
|
|||
const boost::optional<cryptonote::network_type> & network_type){
|
||||
TREZOR_AUTO_LOCK_CMD();
|
||||
require_connected();
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
require_initialized();
|
||||
|
||||
auto req = std::make_shared<messages::monero::MoneroGetWatchKey>();
|
||||
|
@ -274,7 +274,7 @@ namespace trezor {
|
|||
{
|
||||
TREZOR_AUTO_LOCK_CMD();
|
||||
require_connected();
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
require_initialized();
|
||||
|
||||
auto req = protocol::tx::get_tx_key(tx_aux_data);
|
||||
|
@ -294,15 +294,15 @@ namespace trezor {
|
|||
|
||||
TREZOR_AUTO_LOCK_CMD();
|
||||
require_connected();
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
require_initialized();
|
||||
|
||||
std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> req;
|
||||
|
||||
std::vector<protocol::ki::MoneroTransferDetails> mtds;
|
||||
std::vector<protocol::ki::MoneroExportedKeyImage> kis;
|
||||
protocol::ki::key_image_data(wallet, transfers, mtds);
|
||||
protocol::ki::generate_commitment(mtds, transfers, req);
|
||||
protocol::ki::key_image_data(wallet, transfers, mtds, client_version() <= 1);
|
||||
protocol::ki::generate_commitment(mtds, transfers, req, client_version() <= 1);
|
||||
|
||||
EVENT_PROGRESS(0.);
|
||||
this->set_msg_addr<messages::monero::MoneroKeyImageExportInitRequest>(req.get());
|
||||
|
@ -386,7 +386,7 @@ namespace trezor {
|
|||
|
||||
void device_trezor::live_refresh_start_unsafe()
|
||||
{
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
require_initialized();
|
||||
|
||||
auto req = std::make_shared<messages::monero::MoneroLiveRefreshStartRequest>();
|
||||
|
@ -492,7 +492,7 @@ namespace trezor {
|
|||
|
||||
TREZOR_AUTO_LOCK_CMD();
|
||||
require_connected();
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
require_initialized();
|
||||
transaction_versions_check(unsigned_tx, aux_data);
|
||||
|
||||
|
@ -514,7 +514,7 @@ namespace trezor {
|
|||
auto & cpend = signed_tx.ptx.back();
|
||||
cpend.tx = cdata.tx;
|
||||
cpend.dust = 0;
|
||||
cpend.fee = 0;
|
||||
cpend.fee = cpend.tx.rct_signatures.txnFee;
|
||||
cpend.dust_added_to_fee = false;
|
||||
cpend.change_dts = cdata.tx_data.change_dts;
|
||||
cpend.selected_transfers = cdata.tx_data.selected_transfers;
|
||||
|
@ -524,6 +524,7 @@ namespace trezor {
|
|||
|
||||
// Transaction check
|
||||
try {
|
||||
MDEBUG("signed transaction: " << cryptonote::get_transaction_hash(cpend.tx) << ENDL << cryptonote::obj_to_json_str(cpend.tx) << ENDL);
|
||||
transaction_check(cdata, aux_data);
|
||||
} catch(const std::exception &e){
|
||||
throw exc::ProtocolException(std::string("Transaction verification failed: ") + e.what());
|
||||
|
@ -582,7 +583,7 @@ namespace trezor {
|
|||
|
||||
require_connected();
|
||||
if (idx > 0)
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
|
||||
require_initialized();
|
||||
EVENT_PROGRESS(0, 1, 1);
|
||||
|
@ -670,28 +671,42 @@ namespace trezor {
|
|||
#undef EVENT_PROGRESS
|
||||
}
|
||||
|
||||
void device_trezor::transaction_versions_check(const ::tools::wallet2::unsigned_tx_set & unsigned_tx, hw::tx_aux_data & aux_data)
|
||||
unsigned device_trezor::client_version()
|
||||
{
|
||||
auto trezor_version = get_version();
|
||||
unsigned client_version = 1; // default client version for tx
|
||||
|
||||
if (trezor_version <= pack_version(2, 0, 10)){
|
||||
client_version = 0;
|
||||
throw exc::TrezorException("Trezor firmware 2.0.10 and lower are not supported. Please update.");
|
||||
}
|
||||
|
||||
// default client version, higher versions check will be added
|
||||
unsigned client_version = 1;
|
||||
|
||||
#ifdef WITH_TREZOR_DEBUGGING
|
||||
// Override client version for tests
|
||||
const char *env_trezor_client_version = nullptr;
|
||||
if ((env_trezor_client_version = getenv("TREZOR_CLIENT_VERSION")) != nullptr){
|
||||
auto succ = epee::string_tools::get_xtype_from_string(client_version, env_trezor_client_version);
|
||||
if (succ){
|
||||
MINFO("Trezor client version overriden by TREZOR_CLIENT_VERSION to: " << client_version);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return client_version;
|
||||
}
|
||||
|
||||
void device_trezor::transaction_versions_check(const ::tools::wallet2::unsigned_tx_set & unsigned_tx, hw::tx_aux_data & aux_data)
|
||||
{
|
||||
unsigned cversion = client_version();
|
||||
|
||||
if (aux_data.client_version){
|
||||
auto wanted_client_version = aux_data.client_version.get();
|
||||
if (wanted_client_version > client_version){
|
||||
throw exc::TrezorException("Trezor firmware 2.0.10 and lower does not support current transaction sign protocol. Please update.");
|
||||
if (wanted_client_version > cversion){
|
||||
throw exc::TrezorException("Trezor has too old firmware version. Please update.");
|
||||
} else {
|
||||
client_version = wanted_client_version;
|
||||
cversion = wanted_client_version;
|
||||
}
|
||||
}
|
||||
aux_data.client_version = client_version;
|
||||
|
||||
if (client_version == 0 && aux_data.bp_version && aux_data.bp_version.get() != 1){
|
||||
throw exc::TrezorException("Trezor firmware 2.0.10 and lower does not support current transaction sign protocol (BPv2+). Please update.");
|
||||
}
|
||||
aux_data.client_version = cversion;
|
||||
}
|
||||
|
||||
void device_trezor::transaction_pre_check(std::shared_ptr<messages::monero::MoneroTransactionInitRequest> init_msg)
|
||||
|
|
|
@ -67,10 +67,11 @@ namespace trezor {
|
|||
bool m_live_refresh_enabled;
|
||||
size_t m_num_transations_to_sign;
|
||||
|
||||
unsigned client_version();
|
||||
void transaction_versions_check(const ::tools::wallet2::unsigned_tx_set & unsigned_tx, hw::tx_aux_data & aux_data);
|
||||
void transaction_pre_check(std::shared_ptr<messages::monero::MoneroTransactionInitRequest> init_msg);
|
||||
void transaction_check(const protocol::tx::TData & tdata, const hw::tx_aux_data & aux_data);
|
||||
void device_state_reset_unsafe() override;
|
||||
void device_state_initialize_unsafe() override;
|
||||
void live_refresh_start_unsafe();
|
||||
void live_refresh_finish_unsafe();
|
||||
void live_refresh_thread_main();
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
//
|
||||
|
||||
#include "device_trezor_base.hpp"
|
||||
#include "memwipe.h"
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
@ -151,7 +152,7 @@ namespace trezor {
|
|||
|
||||
bool device_trezor_base::disconnect() {
|
||||
TREZOR_AUTO_LOCK_DEVICE();
|
||||
m_device_state.clear();
|
||||
m_device_session_id.clear();
|
||||
m_features.reset();
|
||||
|
||||
if (m_transport){
|
||||
|
@ -292,8 +293,8 @@ namespace trezor {
|
|||
case messages::MessageType_PassphraseRequest:
|
||||
on_passphrase_request(input, dynamic_cast<const messages::common::PassphraseRequest*>(input.m_msg.get()));
|
||||
return true;
|
||||
case messages::MessageType_PassphraseStateRequest:
|
||||
on_passphrase_state_request(input, dynamic_cast<const messages::common::PassphraseStateRequest*>(input.m_msg.get()));
|
||||
case messages::MessageType_Deprecated_PassphraseStateRequest:
|
||||
on_passphrase_state_request(input, dynamic_cast<const messages::common::Deprecated_PassphraseStateRequest*>(input.m_msg.get()));
|
||||
return true;
|
||||
case messages::MessageType_PinMatrixRequest:
|
||||
on_pin_request(input, dynamic_cast<const messages::common::PinMatrixRequest*>(input.m_msg.get()));
|
||||
|
@ -361,23 +362,34 @@ namespace trezor {
|
|||
return false;
|
||||
}
|
||||
|
||||
void device_trezor_base::device_state_reset_unsafe()
|
||||
void device_trezor_base::device_state_initialize_unsafe()
|
||||
{
|
||||
require_connected();
|
||||
std::string tmp_session_id;
|
||||
auto initMsg = std::make_shared<messages::management::Initialize>();
|
||||
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
|
||||
memwipe(&tmp_session_id[0], tmp_session_id.size());
|
||||
});
|
||||
|
||||
if(!m_device_state.empty()) {
|
||||
initMsg->set_allocated_state(&m_device_state);
|
||||
if(!m_device_session_id.empty()) {
|
||||
tmp_session_id.assign(m_device_session_id.data(), m_device_session_id.size());
|
||||
initMsg->set_allocated_session_id(&tmp_session_id);
|
||||
}
|
||||
|
||||
m_features = this->client_exchange<messages::management::Features>(initMsg);
|
||||
initMsg->release_state();
|
||||
if (m_features->has_session_id()){
|
||||
m_device_session_id = m_features->session_id();
|
||||
} else {
|
||||
m_device_session_id.clear();
|
||||
}
|
||||
|
||||
initMsg->release_session_id();
|
||||
}
|
||||
|
||||
void device_trezor_base::device_state_reset()
|
||||
{
|
||||
TREZOR_AUTO_LOCK_CMD();
|
||||
device_state_reset_unsafe();
|
||||
device_state_initialize_unsafe();
|
||||
}
|
||||
|
||||
#ifdef WITH_TREZOR_DEBUGGING
|
||||
|
@ -441,48 +453,89 @@ namespace trezor {
|
|||
pin = m_pin;
|
||||
}
|
||||
|
||||
// TODO: remove PIN from memory
|
||||
std::string pin_field;
|
||||
messages::common::PinMatrixAck m;
|
||||
if (pin) {
|
||||
m.set_pin(pin.get().data(), pin.get().size());
|
||||
pin_field.assign(pin->data(), pin->size());
|
||||
m.set_allocated_pin(&pin_field);
|
||||
}
|
||||
|
||||
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
|
||||
m.release_pin();
|
||||
if (!pin_field.empty()){
|
||||
memwipe(&pin_field[0], pin_field.size());
|
||||
}
|
||||
});
|
||||
|
||||
resp = call_raw(&m);
|
||||
}
|
||||
|
||||
void device_trezor_base::on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
|
||||
MDEBUG("on_passhprase_request, on device: " << msg->on_device());
|
||||
boost::optional<epee::wipeable_string> passphrase;
|
||||
TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, msg->on_device());
|
||||
MDEBUG("on_passhprase_request");
|
||||
|
||||
// Backward compatibility, migration clause.
|
||||
if (msg->has__on_device() && msg->_on_device()){
|
||||
messages::common::PassphraseAck m;
|
||||
resp = call_raw(&m);
|
||||
return;
|
||||
}
|
||||
|
||||
bool on_device = true;
|
||||
if (msg->has__on_device() && !msg->_on_device()){
|
||||
on_device = false; // do not enter on device, old devices.
|
||||
}
|
||||
|
||||
if (on_device && m_features && m_features->capabilities_size() > 0){
|
||||
on_device = false;
|
||||
for (auto it = m_features->capabilities().begin(); it != m_features->capabilities().end(); it++) {
|
||||
if (*it == messages::management::Features::Capability_PassphraseEntry){
|
||||
on_device = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<epee::wipeable_string> passphrase;
|
||||
TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, on_device);
|
||||
|
||||
std::string passphrase_field;
|
||||
messages::common::PassphraseAck m;
|
||||
m.set_on_device(on_device);
|
||||
if (!on_device) {
|
||||
if (!passphrase && m_passphrase) {
|
||||
passphrase = m_passphrase;
|
||||
}
|
||||
|
||||
if (m_passphrase) {
|
||||
m_passphrase = boost::none;
|
||||
|
||||
messages::common::PassphraseAck m;
|
||||
if (!msg->on_device() && passphrase){
|
||||
// TODO: remove passphrase from memory
|
||||
m.set_passphrase(passphrase.get().data(), passphrase.get().size());
|
||||
}
|
||||
|
||||
if (!m_device_state.empty()){
|
||||
m.set_allocated_state(&m_device_state);
|
||||
if (passphrase) {
|
||||
passphrase_field.assign(passphrase->data(), passphrase->size());
|
||||
m.set_allocated_passphrase(&passphrase_field);
|
||||
}
|
||||
}
|
||||
|
||||
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
|
||||
m.release_passphrase();
|
||||
if (!passphrase_field.empty()){
|
||||
memwipe(&passphrase_field[0], passphrase_field.size());
|
||||
}
|
||||
});
|
||||
|
||||
resp = call_raw(&m);
|
||||
m.release_state();
|
||||
}
|
||||
|
||||
void device_trezor_base::on_passphrase_state_request(GenericMessage & resp, const messages::common::PassphraseStateRequest * msg)
|
||||
void device_trezor_base::on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg)
|
||||
{
|
||||
MDEBUG("on_passhprase_state_request");
|
||||
CHECK_AND_ASSERT_THROW_MES(msg, "Empty message");
|
||||
|
||||
m_device_state = msg->state();
|
||||
messages::common::PassphraseStateAck m;
|
||||
if (msg->has_state()) {
|
||||
m_device_session_id = msg->state();
|
||||
}
|
||||
messages::common::Deprecated_PassphraseStateAck m;
|
||||
resp = call_raw(&m);
|
||||
}
|
||||
|
||||
|
@ -510,7 +563,7 @@ namespace trezor {
|
|||
}
|
||||
|
||||
auto msg = std::make_shared<messages::management::LoadDevice>();
|
||||
msg->set_mnemonic(mnemonic);
|
||||
msg->add_mnemonics(mnemonic);
|
||||
msg->set_pin(pin);
|
||||
msg->set_passphrase_protection(passphrase_protection);
|
||||
msg->set_label(label);
|
||||
|
@ -535,7 +588,8 @@ namespace trezor {
|
|||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<epee::wipeable_string> trezor_debug_callback::on_passphrase_request(bool on_device) {
|
||||
boost::optional<epee::wipeable_string> trezor_debug_callback::on_passphrase_request(bool & on_device) {
|
||||
on_device = true;
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace trezor {
|
|||
|
||||
void on_button_request(uint64_t code=0) override;
|
||||
boost::optional<epee::wipeable_string> on_pin_request() override;
|
||||
boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) override;
|
||||
boost::optional<epee::wipeable_string> on_passphrase_request(bool & on_device) override;
|
||||
void on_passphrase_state_request(const std::string &state);
|
||||
void on_disconnect();
|
||||
protected:
|
||||
|
@ -94,7 +94,7 @@ namespace trezor {
|
|||
|
||||
std::string m_full_name;
|
||||
std::vector<unsigned int> m_wallet_deriv_path;
|
||||
std::string m_device_state; // returned after passphrase entry, session
|
||||
epee::wipeable_string m_device_session_id; // returned after passphrase entry, session
|
||||
std::shared_ptr<messages::management::Features> m_features; // features from the last device reset
|
||||
boost::optional<epee::wipeable_string> m_pin;
|
||||
boost::optional<epee::wipeable_string> m_passphrase;
|
||||
|
@ -117,7 +117,7 @@ namespace trezor {
|
|||
void require_initialized() const;
|
||||
void call_ping_unsafe();
|
||||
void test_ping();
|
||||
virtual void device_state_reset_unsafe();
|
||||
virtual void device_state_initialize_unsafe();
|
||||
void ensure_derivation_path() noexcept;
|
||||
|
||||
// Communication methods
|
||||
|
@ -315,7 +315,7 @@ namespace trezor {
|
|||
void on_button_pressed();
|
||||
void on_pin_request(GenericMessage & resp, const messages::common::PinMatrixRequest * msg);
|
||||
void on_passphrase_request(GenericMessage & resp, const messages::common::PassphraseRequest * msg);
|
||||
void on_passphrase_state_request(GenericMessage & resp, const messages::common::PassphraseStateRequest * msg);
|
||||
void on_passphrase_state_request(GenericMessage & resp, const messages::common::Deprecated_PassphraseStateRequest * msg);
|
||||
|
||||
#ifdef WITH_TREZOR_DEBUGGING
|
||||
void set_debug(bool debug){
|
||||
|
|
|
@ -71,9 +71,9 @@ namespace trezor{
|
|||
call(decision, boost::none, true);
|
||||
}
|
||||
|
||||
void DebugLink::input_swipe(bool swipe){
|
||||
void DebugLink::input_swipe(messages::debug::DebugLinkDecision_DebugSwipeDirection direction){
|
||||
messages::debug::DebugLinkDecision decision;
|
||||
decision.set_up_down(swipe);
|
||||
decision.set_swipe(direction);
|
||||
call(decision, boost::none, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace trezor {
|
|||
std::shared_ptr<messages::debug::DebugLinkState> state();
|
||||
void input_word(const std::string & word);
|
||||
void input_button(bool button);
|
||||
void input_swipe(bool swipe);
|
||||
void input_swipe(messages::debug::DebugLinkDecision_DebugSwipeDirection direction);
|
||||
void press_yes() { input_button(true); }
|
||||
void press_no() { input_button(false); }
|
||||
void stop();
|
||||
|
|
|
@ -145,7 +145,8 @@ namespace ki {
|
|||
|
||||
bool key_image_data(wallet_shim * wallet,
|
||||
const std::vector<tools::wallet2::transfer_details> & transfers,
|
||||
std::vector<MoneroTransferDetails> & res)
|
||||
std::vector<MoneroTransferDetails> & res,
|
||||
bool need_all_additionals)
|
||||
{
|
||||
for(auto & td : transfers){
|
||||
::crypto::public_key tx_pub_key = wallet->get_tx_pub_key_from_received_outs(td);
|
||||
|
@ -157,9 +158,15 @@ namespace ki {
|
|||
cres.set_out_key(key_to_string(boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key));
|
||||
cres.set_tx_pub_key(key_to_string(tx_pub_key));
|
||||
cres.set_internal_output_index(td.m_internal_output_index);
|
||||
cres.set_sub_addr_major(td.m_subaddr_index.major);
|
||||
cres.set_sub_addr_minor(td.m_subaddr_index.minor);
|
||||
if (need_all_additionals) {
|
||||
for (auto &aux : additional_tx_pub_keys) {
|
||||
cres.add_additional_tx_pub_keys(key_to_string(aux));
|
||||
}
|
||||
} else if (!additional_tx_pub_keys.empty() && additional_tx_pub_keys.size() > td.m_internal_output_index) {
|
||||
cres.add_additional_tx_pub_keys(key_to_string(additional_tx_pub_keys[td.m_internal_output_index]));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -188,7 +195,8 @@ namespace ki {
|
|||
|
||||
void generate_commitment(std::vector<MoneroTransferDetails> & mtds,
|
||||
const std::vector<tools::wallet2::transfer_details> & transfers,
|
||||
std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req)
|
||||
std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req,
|
||||
bool need_subaddr_indices)
|
||||
{
|
||||
req = std::make_shared<messages::monero::MoneroKeyImageExportInitRequest>();
|
||||
|
||||
|
@ -213,6 +221,7 @@ namespace ki {
|
|||
st.insert(cur.m_subaddr_index.minor);
|
||||
}
|
||||
|
||||
if (need_subaddr_indices) {
|
||||
for (auto &x: sub_indices) {
|
||||
auto subs = req->add_subs();
|
||||
subs->set_account(x.first);
|
||||
|
@ -221,6 +230,7 @@ namespace ki {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void live_refresh_ack(const ::crypto::secret_key & view_key_priv,
|
||||
const ::crypto::public_key& out_key,
|
||||
|
@ -283,26 +293,6 @@ namespace tx {
|
|||
translate_address(dst->mutable_addr(), &(src->addr));
|
||||
}
|
||||
|
||||
void translate_src_entry(MoneroTransactionSourceEntry * dst, const cryptonote::tx_source_entry * src){
|
||||
for(auto & cur : src->outputs){
|
||||
auto out = dst->add_outputs();
|
||||
out->set_idx(cur.first);
|
||||
translate_rct_key(out->mutable_key(), &(cur.second));
|
||||
}
|
||||
|
||||
dst->set_real_output(src->real_output);
|
||||
dst->set_real_out_tx_key(key_to_string(src->real_out_tx_key));
|
||||
for(auto & cur : src->real_out_additional_tx_keys){
|
||||
dst->add_real_out_additional_tx_keys(key_to_string(cur));
|
||||
}
|
||||
|
||||
dst->set_real_output_in_tx_index(src->real_output_in_tx_index);
|
||||
dst->set_amount(src->amount);
|
||||
dst->set_rct(src->rct);
|
||||
dst->set_mask(key_to_string(src->mask));
|
||||
translate_klrki(dst->mutable_multisig_klrki(), &(src->multisig_kLRki));
|
||||
}
|
||||
|
||||
void translate_klrki(MoneroMultisigKLRki * dst, const rct::multisig_kLRki * src){
|
||||
dst->set_k(key_to_string(src->k));
|
||||
dst->set_l(key_to_string(src->L));
|
||||
|
@ -369,6 +359,31 @@ namespace tx {
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string compute_sealing_key(const std::string & master_key, size_t idx, bool is_iv)
|
||||
{
|
||||
// master-key-32B || domain-sep-12B || index-4B
|
||||
uint8_t hash[32] = {0};
|
||||
KECCAK_CTX ctx;
|
||||
std::string sep = is_iv ? "sig-iv" : "sig-key";
|
||||
std::string idx_data = tools::get_varint_data(idx);
|
||||
if (idx_data.size() > 4){
|
||||
throw std::invalid_argument("index is too big");
|
||||
}
|
||||
|
||||
keccak_init(&ctx);
|
||||
keccak_update(&ctx, (const uint8_t *) master_key.data(), master_key.size());
|
||||
keccak_update(&ctx, (const uint8_t *) sep.data(), sep.size());
|
||||
keccak_update(&ctx, hash, 12 - sep.size());
|
||||
keccak_update(&ctx, (const uint8_t *) idx_data.data(), idx_data.size());
|
||||
if (idx_data.size() < 4) {
|
||||
keccak_update(&ctx, hash, 4 - idx_data.size());
|
||||
}
|
||||
|
||||
keccak_finish(&ctx, hash);
|
||||
keccak(hash, sizeof(hash), hash, sizeof(hash));
|
||||
return std::string((const char*) hash, 32);
|
||||
}
|
||||
|
||||
TData::TData() {
|
||||
rsig_type = 0;
|
||||
bp_version = 0;
|
||||
|
@ -383,7 +398,7 @@ namespace tx {
|
|||
m_unsigned_tx = unsigned_tx;
|
||||
m_aux_data = aux_data;
|
||||
m_tx_idx = tx_idx;
|
||||
m_ct.tx_data = cur_tx();
|
||||
m_ct.tx_data = cur_src_tx();
|
||||
m_multisig = false;
|
||||
m_client_version = 1;
|
||||
}
|
||||
|
@ -451,6 +466,41 @@ namespace tx {
|
|||
}
|
||||
}
|
||||
|
||||
void Signer::set_tx_input(MoneroTransactionSourceEntry * dst, size_t idx, bool need_ring_keys, bool need_ring_indices){
|
||||
const cryptonote::tx_source_entry & src = cur_tx().sources[idx];
|
||||
const tools::wallet2::transfer_details & transfer = get_source_transfer(idx);
|
||||
|
||||
dst->set_real_output(src.real_output);
|
||||
for(size_t i = 0; i < src.outputs.size(); ++i){
|
||||
auto & cur = src.outputs[i];
|
||||
auto out = dst->add_outputs();
|
||||
|
||||
if (i == src.real_output || need_ring_indices || client_version() <= 1) {
|
||||
out->set_idx(cur.first);
|
||||
}
|
||||
if (i == src.real_output || need_ring_keys || client_version() <= 1) {
|
||||
translate_rct_key(out->mutable_key(), &(cur.second));
|
||||
}
|
||||
}
|
||||
|
||||
dst->set_real_out_tx_key(key_to_string(src.real_out_tx_key));
|
||||
dst->set_real_output_in_tx_index(src.real_output_in_tx_index);
|
||||
|
||||
if (client_version() <= 1) {
|
||||
for (auto &cur : src.real_out_additional_tx_keys) {
|
||||
dst->add_real_out_additional_tx_keys(key_to_string(cur));
|
||||
}
|
||||
} else if (!src.real_out_additional_tx_keys.empty()) {
|
||||
dst->add_real_out_additional_tx_keys(key_to_string(src.real_out_additional_tx_keys.at(src.real_output_in_tx_index)));
|
||||
}
|
||||
|
||||
dst->set_amount(src.amount);
|
||||
dst->set_rct(src.rct);
|
||||
dst->set_mask(key_to_string(src.mask));
|
||||
translate_klrki(dst->mutable_multisig_klrki(), &(src.multisig_kLRki));
|
||||
dst->set_subaddr_minor(transfer.m_subaddr_index.minor);
|
||||
}
|
||||
|
||||
void Signer::compute_integrated_indices(TsxData * tsx_data){
|
||||
if (m_aux_data == nullptr || m_aux_data->tx_recipients.empty()){
|
||||
return;
|
||||
|
@ -492,6 +542,7 @@ namespace tx {
|
|||
// extract payment ID from construction data
|
||||
auto & tsx_data = m_ct.tsx_data;
|
||||
auto & tx = cur_tx();
|
||||
const size_t input_size = tx.sources.size();
|
||||
|
||||
m_ct.tx.version = 2;
|
||||
m_ct.tx.unlock_time = tx.unlock_time;
|
||||
|
@ -500,12 +551,20 @@ namespace tx {
|
|||
tsx_data.set_version(1);
|
||||
tsx_data.set_client_version(client_version());
|
||||
tsx_data.set_unlock_time(tx.unlock_time);
|
||||
tsx_data.set_num_inputs(static_cast<google::protobuf::uint32>(tx.sources.size()));
|
||||
tsx_data.set_num_inputs(static_cast<google::protobuf::uint32>(input_size));
|
||||
tsx_data.set_mixin(static_cast<google::protobuf::uint32>(tx.sources[0].outputs.size() - 1));
|
||||
tsx_data.set_account(tx.subaddr_account);
|
||||
tsx_data.set_monero_version(std::string(MONERO_VERSION) + "|" + MONERO_VERSION_TAG);
|
||||
tsx_data.set_hard_fork(m_aux_data->hard_fork ? m_aux_data->hard_fork.get() : 0);
|
||||
|
||||
if (client_version() <= 1){
|
||||
assign_to_repeatable(tsx_data.mutable_minor_indices(), tx.subaddr_indices.begin(), tx.subaddr_indices.end());
|
||||
}
|
||||
|
||||
// TODO: use HF_VERSION_CLSAG after CLSAG is merged
|
||||
if (tsx_data.hard_fork() >= 13){
|
||||
throw exc::ProtocolException("CLSAG is not yet implemented");
|
||||
}
|
||||
|
||||
// Rsig decision
|
||||
auto rsig_data = tsx_data.mutable_rsig_data();
|
||||
|
@ -525,6 +584,11 @@ namespace tx {
|
|||
translate_dst_entry(dst, &cur);
|
||||
}
|
||||
|
||||
m_ct.source_permutation.clear();
|
||||
for (size_t n = 0; n < input_size; ++n){
|
||||
m_ct.source_permutation.push_back(n);
|
||||
}
|
||||
|
||||
compute_integrated_indices(&tsx_data);
|
||||
|
||||
int64_t fee = 0;
|
||||
|
@ -559,7 +623,7 @@ namespace tx {
|
|||
CHECK_AND_ASSERT_THROW_MES(idx < cur_tx().sources.size(), "Invalid source index");
|
||||
m_ct.cur_input_idx = idx;
|
||||
auto res = std::make_shared<messages::monero::MoneroTransactionSetInputRequest>();
|
||||
translate_src_entry(res->mutable_src_entr(), &(cur_tx().sources[idx]));
|
||||
set_tx_input(res->mutable_src_entr(), idx, false, true);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -582,11 +646,6 @@ namespace tx {
|
|||
void Signer::sort_ki(){
|
||||
const size_t input_size = cur_tx().sources.size();
|
||||
|
||||
m_ct.source_permutation.clear();
|
||||
for (size_t n = 0; n < input_size; ++n){
|
||||
m_ct.source_permutation.push_back(n);
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(m_ct.tx.vin.size() == input_size, "Invalid vector size");
|
||||
std::sort(m_ct.source_permutation.begin(), m_ct.source_permutation.end(), [&](const size_t i0, const size_t i1) {
|
||||
const cryptonote::txin_to_key &tk0 = boost::get<cryptonote::txin_to_key>(m_ct.tx.vin[i0]);
|
||||
|
@ -614,6 +673,9 @@ namespace tx {
|
|||
|
||||
std::shared_ptr<messages::monero::MoneroTransactionInputsPermutationRequest> Signer::step_permutation(){
|
||||
sort_ki();
|
||||
if (client_version() >= 2){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto res = std::make_shared<messages::monero::MoneroTransactionInputsPermutationRequest>();
|
||||
assign_to_repeatable(res->mutable_perm(), m_ct.source_permutation.begin(), m_ct.source_permutation.end());
|
||||
|
@ -634,17 +696,10 @@ namespace tx {
|
|||
auto tx = m_ct.tx_data;
|
||||
auto res = std::make_shared<messages::monero::MoneroTransactionInputViniRequest>();
|
||||
auto & vini = m_ct.tx.vin[idx];
|
||||
translate_src_entry(res->mutable_src_entr(), &(tx.sources[idx]));
|
||||
set_tx_input(res->mutable_src_entr(), idx, false, false);
|
||||
res->set_vini(cryptonote::t_serializable_object_to_blob(vini));
|
||||
res->set_vini_hmac(m_ct.tx_in_hmacs[idx]);
|
||||
|
||||
if (client_version() == 0) {
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs.size(), "Invalid transaction index");
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs_hmac.size(), "Invalid transaction index");
|
||||
res->set_pseudo_out(m_ct.pseudo_outs[idx]);
|
||||
res->set_pseudo_out_hmac(m_ct.pseudo_outs_hmac[idx]);
|
||||
}
|
||||
|
||||
res->set_orig_idx(m_ct.source_permutation[idx]);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -657,31 +712,6 @@ namespace tx {
|
|||
}
|
||||
|
||||
void Signer::step_all_inputs_set_ack(std::shared_ptr<const messages::monero::MoneroTransactionAllInputsSetAck> ack){
|
||||
if (client_version() > 0 || !is_offloading()){
|
||||
return;
|
||||
}
|
||||
|
||||
// If offloading, expect rsig configuration.
|
||||
if (!ack->has_rsig_data()){
|
||||
throw exc::ProtocolException("Rsig offloading requires rsig param");
|
||||
}
|
||||
|
||||
auto & rsig_data = ack->rsig_data();
|
||||
if (!rsig_data.has_mask()){
|
||||
throw exc::ProtocolException("Gamma masks not present in offloaded version");
|
||||
}
|
||||
|
||||
auto & mask = rsig_data.mask();
|
||||
if (mask.size() != 32 * num_outputs()){
|
||||
throw exc::ProtocolException("Invalid number of gamma masks");
|
||||
}
|
||||
|
||||
m_ct.rsig_gamma.reserve(num_outputs());
|
||||
for(size_t c=0; c < num_outputs(); ++c){
|
||||
rct::key cmask{};
|
||||
memcpy(cmask.bytes, mask.data() + c * 32, 32);
|
||||
m_ct.rsig_gamma.emplace_back(cmask);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<messages::monero::MoneroTransactionSetOutputRequest> Signer::step_set_output(size_t idx){
|
||||
|
@ -696,15 +726,6 @@ namespace tx {
|
|||
auto & cur_dst = m_ct.tx_data.splitted_dsts[idx];
|
||||
translate_dst_entry(res->mutable_dst_entr(), &cur_dst);
|
||||
res->set_dst_entr_hmac(m_ct.tx_out_entr_hmacs[idx]);
|
||||
|
||||
// Range sig offloading to the host
|
||||
// ClientV0 sends offloaded BP with the last message in the batch.
|
||||
// ClientV1 needs additional message after the last message in the batch as BP uses deterministic masks.
|
||||
if (client_version() == 0 && is_offloading() && should_compute_bp_now()) {
|
||||
auto rsig_data = res->mutable_rsig_data();
|
||||
compute_bproof(*rsig_data);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -814,7 +835,7 @@ namespace tx {
|
|||
}
|
||||
|
||||
std::shared_ptr<messages::monero::MoneroTransactionSetOutputRequest> Signer::step_rsig(size_t idx){
|
||||
if (client_version() == 0 || !is_offloading() || !should_compute_bp_now()){
|
||||
if (!is_offloading() || !should_compute_bp_now()){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -917,11 +938,12 @@ namespace tx {
|
|||
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.spend_encs.size(), "Invalid transaction index");
|
||||
|
||||
auto res = std::make_shared<messages::monero::MoneroTransactionSignInputRequest>();
|
||||
translate_src_entry(res->mutable_src_entr(), &(m_ct.tx_data.sources[idx]));
|
||||
set_tx_input(res->mutable_src_entr(), idx, true, true);
|
||||
res->set_vini(cryptonote::t_serializable_object_to_blob(m_ct.tx.vin[idx]));
|
||||
res->set_vini_hmac(m_ct.tx_in_hmacs[idx]);
|
||||
res->set_pseudo_out_alpha(m_ct.alphas[idx]);
|
||||
res->set_spend_key(m_ct.spend_encs[idx]);
|
||||
res->set_orig_idx(m_ct.source_permutation[idx]);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs.size(), "Invalid transaction index");
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.pseudo_outs_hmac.size(), "Invalid transaction index");
|
||||
|
@ -931,10 +953,7 @@ namespace tx {
|
|||
}
|
||||
|
||||
void Signer::step_sign_input_ack(std::shared_ptr<const messages::monero::MoneroTransactionSignInputAck> ack){
|
||||
rct::mgSig mg;
|
||||
if (!cn_deserialize(ack->signature(), mg)){
|
||||
throw exc::ProtocolException("Cannot deserialize mg[i]");
|
||||
}
|
||||
m_ct.signatures.push_back(ack->signature());
|
||||
|
||||
// Sync updated pseudo_outputs, client_version>=1, HF10+
|
||||
if (client_version() >= 1 && ack->has_pseudo_out()){
|
||||
|
@ -948,12 +967,9 @@ namespace tx {
|
|||
string_to_key(m_ct.rv->pseudoOuts[m_ct.cur_input_idx], ack->pseudo_out());
|
||||
}
|
||||
}
|
||||
|
||||
m_ct.rv->p.MGs.push_back(mg);
|
||||
}
|
||||
|
||||
std::shared_ptr<messages::monero::MoneroTransactionFinalRequest> Signer::step_final(){
|
||||
m_ct.tx.rct_signatures = *(m_ct.rv);
|
||||
return std::make_shared<messages::monero::MoneroTransactionFinalRequest>();
|
||||
}
|
||||
|
||||
|
@ -976,6 +992,42 @@ namespace tx {
|
|||
m_ct.enc_salt1 = ack->salt();
|
||||
m_ct.enc_salt2 = ack->rand_mult();
|
||||
m_ct.enc_keys = ack->tx_enc_keys();
|
||||
|
||||
// Opening the sealed signatures
|
||||
if (client_version() >= 3){
|
||||
if(!ack->has_opening_key()){
|
||||
throw exc::ProtocolException("Client version 3+ requires sealed signatures");
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_ct.signatures.size(); ++i){
|
||||
CHECK_AND_ASSERT_THROW_MES(m_ct.signatures[i].size() > crypto::chacha::TAG_SIZE, "Invalid signature size");
|
||||
std::string nonce = compute_sealing_key(ack->opening_key(), i, true);
|
||||
std::string key = compute_sealing_key(ack->opening_key(), i, false);
|
||||
size_t plen = m_ct.signatures[i].size() - crypto::chacha::TAG_SIZE;
|
||||
std::unique_ptr<uint8_t[]> plaintext(new uint8_t[plen]);
|
||||
uint8_t * buff = plaintext.get();
|
||||
|
||||
protocol::crypto::chacha::decrypt(
|
||||
m_ct.signatures[i].data(),
|
||||
m_ct.signatures[i].size(),
|
||||
reinterpret_cast<const uint8_t *>(key.data()),
|
||||
reinterpret_cast<const uint8_t *>(nonce.data()),
|
||||
reinterpret_cast<char *>(buff), &plen);
|
||||
m_ct.signatures[i].assign(reinterpret_cast<const char *>(buff), plen);
|
||||
}
|
||||
}
|
||||
|
||||
// CLSAG support comes here once it is merged to the Monero
|
||||
m_ct.rv->p.MGs.reserve(m_ct.signatures.size());
|
||||
for(size_t i = 0; i < m_ct.signatures.size(); ++i) {
|
||||
rct::mgSig mg;
|
||||
if (!cn_deserialize(m_ct.signatures[i], mg)) {
|
||||
throw exc::ProtocolException("Cannot deserialize mg[i]");
|
||||
}
|
||||
m_ct.rv->p.MGs.push_back(mg);
|
||||
}
|
||||
|
||||
m_ct.tx.rct_signatures = *(m_ct.rv);
|
||||
}
|
||||
|
||||
std::string Signer::store_tx_aux_info(){
|
||||
|
|
|
@ -118,7 +118,8 @@ namespace ki {
|
|||
*/
|
||||
bool key_image_data(wallet_shim * wallet,
|
||||
const std::vector<tools::wallet2::transfer_details> & transfers,
|
||||
std::vector<MoneroTransferDetails> & res);
|
||||
std::vector<MoneroTransferDetails> & res,
|
||||
bool need_all_additionals=false);
|
||||
|
||||
/**
|
||||
* Computes a hash over MoneroTransferDetails. Commitment used in the KI sync.
|
||||
|
@ -130,7 +131,8 @@ namespace ki {
|
|||
*/
|
||||
void generate_commitment(std::vector<MoneroTransferDetails> & mtds,
|
||||
const std::vector<tools::wallet2::transfer_details> & transfers,
|
||||
std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req);
|
||||
std::shared_ptr<messages::monero::MoneroKeyImageExportInitRequest> & req,
|
||||
bool need_subaddr_indices=false);
|
||||
|
||||
/**
|
||||
* Processes Live refresh step response, parses KI, checks the signature
|
||||
|
@ -158,13 +160,13 @@ namespace tx {
|
|||
|
||||
void translate_address(MoneroAccountPublicAddress * dst, const cryptonote::account_public_address * src);
|
||||
void translate_dst_entry(MoneroTransactionDestinationEntry * dst, const cryptonote::tx_destination_entry * src);
|
||||
void translate_src_entry(MoneroTransactionSourceEntry * dst, const cryptonote::tx_source_entry * src);
|
||||
void translate_klrki(MoneroMultisigKLRki * dst, const rct::multisig_kLRki * src);
|
||||
void translate_rct_key(MoneroRctKey * dst, const rct::ctkey * src);
|
||||
std::string hash_addr(const MoneroAccountPublicAddress * addr, boost::optional<uint64_t> amount = boost::none, boost::optional<bool> is_subaddr = boost::none);
|
||||
std::string hash_addr(const std::string & spend_key, const std::string & view_key, boost::optional<uint64_t> amount = boost::none, boost::optional<bool> is_subaddr = boost::none);
|
||||
std::string hash_addr(const ::crypto::public_key * spend_key, const ::crypto::public_key * view_key, boost::optional<uint64_t> amount = boost::none, boost::optional<bool> is_subaddr = boost::none);
|
||||
::crypto::secret_key compute_enc_key(const ::crypto::secret_key & private_view_key, const std::string & aux, const std::string & salt);
|
||||
std::string compute_sealing_key(const std::string & master_key, size_t idx, bool is_iv=false);
|
||||
|
||||
typedef boost::variant<rct::rangeSig, rct::Bulletproof> rsig_v;
|
||||
|
||||
|
@ -198,6 +200,7 @@ namespace tx {
|
|||
std::vector<std::string> pseudo_outs_hmac;
|
||||
std::vector<std::string> couts;
|
||||
std::vector<std::string> couts_dec;
|
||||
std::vector<std::string> signatures;
|
||||
std::vector<rct::key> rsig_gamma;
|
||||
std::string tx_prefix_hash;
|
||||
std::string enc_salt1;
|
||||
|
@ -221,16 +224,33 @@ namespace tx {
|
|||
unsigned m_client_version;
|
||||
bool m_multisig;
|
||||
|
||||
const tx_construction_data & cur_tx(){
|
||||
const tx_construction_data & cur_src_tx() const {
|
||||
CHECK_AND_ASSERT_THROW_MES(m_tx_idx < m_unsigned_tx->txes.size(), "Invalid transaction index");
|
||||
return m_unsigned_tx->txes[m_tx_idx];
|
||||
}
|
||||
|
||||
const tx_construction_data & cur_tx() const {
|
||||
return m_ct.tx_data;
|
||||
}
|
||||
|
||||
const tools::wallet2::transfer_details & get_transfer(size_t idx) const {
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_unsigned_tx->transfers.second.size() + m_unsigned_tx->transfers.first && idx >= m_unsigned_tx->transfers.first, "Invalid transfer index");
|
||||
return m_unsigned_tx->transfers.second[idx - m_unsigned_tx->transfers.first];
|
||||
}
|
||||
|
||||
const tools::wallet2::transfer_details & get_source_transfer(size_t idx) const {
|
||||
const auto & sel_transfers = cur_tx().selected_transfers;
|
||||
CHECK_AND_ASSERT_THROW_MES(idx < m_ct.source_permutation.size(), "Invalid source index - permutation");
|
||||
CHECK_AND_ASSERT_THROW_MES(m_ct.source_permutation[idx] < sel_transfers.size(), "Invalid source index");
|
||||
return get_transfer(sel_transfers.at(m_ct.source_permutation[idx]));
|
||||
}
|
||||
|
||||
void extract_payment_id();
|
||||
void compute_integrated_indices(TsxData * tsx_data);
|
||||
bool should_compute_bp_now() const;
|
||||
void compute_bproof(messages::monero::MoneroTransactionRsigData & rsig_data);
|
||||
void process_bproof(rct::Bulletproof & bproof);
|
||||
void set_tx_input(MoneroTransactionSourceEntry * dst, size_t idx, bool need_ring_keys=false, bool need_ring_indices=false);
|
||||
|
||||
public:
|
||||
Signer(wallet_shim * wallet2, const unsigned_tx_set * unsigned_tx, size_t tx_idx = 0, hw::tx_aux_data * aux_data = nullptr);
|
||||
|
|
|
@ -56,6 +56,11 @@ namespace trezor{
|
|||
return true;
|
||||
}
|
||||
|
||||
bool t_serialize(const epee::wipeable_string & in, std::string & out){
|
||||
out.assign(in.data(), in.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_serialize(const json_val & in, std::string & out){
|
||||
rapidjson::StringBuffer sb;
|
||||
rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
|
||||
|
@ -75,6 +80,11 @@ namespace trezor{
|
|||
return true;
|
||||
}
|
||||
|
||||
bool t_deserialize(std::string & in, epee::wipeable_string & out){
|
||||
out = epee::wipeable_string(in);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_deserialize(const std::string & in, json & out){
|
||||
if (out.Parse(in.c_str()).HasParseError()) {
|
||||
throw exc::CommunicationException("JSON parse error");
|
||||
|
@ -192,61 +202,69 @@ namespace trezor{
|
|||
const auto msg_size = message_size(req);
|
||||
const auto buff_size = serialize_message_buffer_size(msg_size) + 2;
|
||||
|
||||
std::unique_ptr<uint8_t[]> req_buff(new uint8_t[buff_size]);
|
||||
uint8_t * req_buff_raw = req_buff.get();
|
||||
epee::wipeable_string req_buff;
|
||||
epee::wipeable_string chunk_buff;
|
||||
|
||||
req_buff.resize(buff_size);
|
||||
chunk_buff.resize(REPLEN);
|
||||
|
||||
uint8_t * req_buff_raw = reinterpret_cast<uint8_t *>(req_buff.data());
|
||||
uint8_t * chunk_buff_raw = reinterpret_cast<uint8_t *>(chunk_buff.data());
|
||||
|
||||
req_buff_raw[0] = '#';
|
||||
req_buff_raw[1] = '#';
|
||||
|
||||
serialize_message(req, msg_size, req_buff_raw + 2, buff_size - 2);
|
||||
|
||||
size_t offset = 0;
|
||||
uint8_t chunk_buff[REPLEN];
|
||||
|
||||
// Chunk by chunk upload
|
||||
while(offset < buff_size){
|
||||
auto to_copy = std::min((size_t)(buff_size - offset), (size_t)(REPLEN - 1));
|
||||
|
||||
chunk_buff[0] = '?';
|
||||
memcpy(chunk_buff + 1, req_buff_raw + offset, to_copy);
|
||||
chunk_buff_raw[0] = '?';
|
||||
memcpy(chunk_buff_raw + 1, req_buff_raw + offset, to_copy);
|
||||
|
||||
// Pad with zeros
|
||||
if (to_copy < REPLEN - 1){
|
||||
memset(chunk_buff + 1 + to_copy, 0, REPLEN - 1 - to_copy);
|
||||
memset(chunk_buff_raw + 1 + to_copy, 0, REPLEN - 1 - to_copy);
|
||||
}
|
||||
|
||||
transport.write_chunk(chunk_buff, REPLEN);
|
||||
transport.write_chunk(chunk_buff_raw, REPLEN);
|
||||
offset += REPLEN - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolV1::read(Transport & transport, std::shared_ptr<google::protobuf::Message> & msg, messages::MessageType * msg_type){
|
||||
char chunk[REPLEN];
|
||||
epee::wipeable_string chunk_buff;
|
||||
chunk_buff.resize(REPLEN);
|
||||
char * chunk_buff_raw = chunk_buff.data();
|
||||
|
||||
// Initial chunk read
|
||||
size_t nread = transport.read_chunk(chunk, REPLEN);
|
||||
size_t nread = transport.read_chunk(chunk_buff_raw, REPLEN);
|
||||
if (nread != REPLEN){
|
||||
throw exc::CommunicationException("Read chunk has invalid size");
|
||||
}
|
||||
|
||||
if (strncmp(chunk, "?##", 3) != 0){
|
||||
if (memcmp(chunk_buff_raw, "?##", 3) != 0){
|
||||
throw exc::CommunicationException("Malformed chunk");
|
||||
}
|
||||
|
||||
uint16_t tag;
|
||||
uint32_t len;
|
||||
nread -= 3 + 6;
|
||||
deserialize_message_header(chunk + 3, tag, len);
|
||||
deserialize_message_header(chunk_buff_raw + 3, tag, len);
|
||||
|
||||
std::string data_acc(chunk + 3 + 6, nread);
|
||||
epee::wipeable_string data_acc(chunk_buff_raw + 3 + 6, nread);
|
||||
data_acc.reserve(len);
|
||||
|
||||
while(nread < len){
|
||||
const size_t cur = transport.read_chunk(chunk, REPLEN);
|
||||
if (chunk[0] != '?'){
|
||||
const size_t cur = transport.read_chunk(chunk_buff_raw, REPLEN);
|
||||
if (chunk_buff_raw[0] != '?'){
|
||||
throw exc::CommunicationException("Chunk malformed");
|
||||
}
|
||||
|
||||
data_acc.append(chunk + 1, cur - 1);
|
||||
data_acc.append(chunk_buff_raw + 1, cur - 1);
|
||||
nread += cur - 1;
|
||||
}
|
||||
|
||||
|
@ -259,7 +277,7 @@ namespace trezor{
|
|||
}
|
||||
|
||||
std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(tag));
|
||||
if (!msg_wrap->ParseFromArray(data_acc.c_str(), len)){
|
||||
if (!msg_wrap->ParseFromArray(data_acc.data(), len)){
|
||||
throw exc::CommunicationException("Message could not be parsed");
|
||||
}
|
||||
|
||||
|
@ -426,15 +444,16 @@ namespace trezor{
|
|||
|
||||
const auto msg_size = message_size(req);
|
||||
const auto buff_size = serialize_message_buffer_size(msg_size);
|
||||
epee::wipeable_string req_buff;
|
||||
req_buff.resize(buff_size);
|
||||
|
||||
std::unique_ptr<uint8_t[]> req_buff(new uint8_t[buff_size]);
|
||||
uint8_t * req_buff_raw = req_buff.get();
|
||||
uint8_t * req_buff_raw = reinterpret_cast<uint8_t *>(req_buff.data());
|
||||
|
||||
serialize_message(req, msg_size, req_buff_raw, buff_size);
|
||||
|
||||
std::string uri = "/call/" + m_session.get();
|
||||
std::string req_hex = epee::to_hex::string(epee::span<const std::uint8_t>(req_buff_raw, buff_size));
|
||||
std::string res_hex;
|
||||
epee::wipeable_string res_hex;
|
||||
epee::wipeable_string req_hex = epee::to_hex::wipeable_string(epee::span<const std::uint8_t>(req_buff_raw, buff_size));
|
||||
|
||||
bool req_status = invoke_bridge_http(uri, req_hex, res_hex, m_http_client);
|
||||
if (!req_status){
|
||||
|
@ -449,15 +468,15 @@ namespace trezor{
|
|||
throw exc::CommunicationException("Could not read, no response stored");
|
||||
}
|
||||
|
||||
std::string bin_data;
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(m_response.get(), bin_data)){
|
||||
boost::optional<epee::wipeable_string> bin_data = m_response->parse_hexstr();
|
||||
if (!bin_data){
|
||||
throw exc::CommunicationException("Response is not well hexcoded");
|
||||
}
|
||||
|
||||
uint16_t msg_tag;
|
||||
uint32_t msg_len;
|
||||
deserialize_message_header(bin_data.c_str(), msg_tag, msg_len);
|
||||
if (bin_data.size() != msg_len + 6){
|
||||
deserialize_message_header(bin_data->data(), msg_tag, msg_len);
|
||||
if (bin_data->size() != msg_len + 6){
|
||||
throw exc::CommunicationException("Response is not well hexcoded");
|
||||
}
|
||||
|
||||
|
@ -466,7 +485,7 @@ namespace trezor{
|
|||
}
|
||||
|
||||
std::shared_ptr<google::protobuf::Message> msg_wrap(MessageMapper::get_message(msg_tag));
|
||||
if (!msg_wrap->ParseFromArray(bin_data.c_str() + 6, msg_len)){
|
||||
if (!msg_wrap->ParseFromArray(bin_data->data() + 6, msg_len)){
|
||||
throw exc::EncodingException("Response is not well hexcoded");
|
||||
}
|
||||
msg = msg_wrap;
|
||||
|
|
|
@ -66,10 +66,12 @@ namespace trezor {
|
|||
|
||||
// Base HTTP comm serialization.
|
||||
bool t_serialize(const std::string & in, std::string & out);
|
||||
bool t_serialize(const epee::wipeable_string & in, std::string & out);
|
||||
bool t_serialize(const json_val & in, std::string & out);
|
||||
std::string t_serialize(const json_val & in);
|
||||
|
||||
bool t_deserialize(const std::string & in, std::string & out);
|
||||
bool t_deserialize(std::string & in, epee::wipeable_string & out);
|
||||
bool t_deserialize(const std::string & in, json & out);
|
||||
|
||||
// Flexible json serialization. HTTP client tailored for bridge API
|
||||
|
@ -84,6 +86,13 @@ namespace trezor {
|
|||
additional_params.push_back(std::make_pair("Content-Type","application/json; charset=utf-8"));
|
||||
|
||||
const http::http_response_info* pri = nullptr;
|
||||
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
|
||||
if (!req_param.empty()) {
|
||||
memwipe(&req_param[0], req_param.size());
|
||||
}
|
||||
transport.wipe_response();
|
||||
});
|
||||
|
||||
if(!transport.invoke(uri, method, req_param, timeout, &pri, std::move(additional_params)))
|
||||
{
|
||||
MERROR("Failed to invoke http request to " << uri);
|
||||
|
@ -103,7 +112,7 @@ namespace trezor {
|
|||
return false;
|
||||
}
|
||||
|
||||
return t_deserialize(pri->m_body, result_struct);
|
||||
return t_deserialize(const_cast<http::http_response_info*>(pri)->m_body, result_struct);
|
||||
}
|
||||
|
||||
// Forward decl
|
||||
|
@ -186,7 +195,7 @@ namespace trezor {
|
|||
std::string m_bridge_host;
|
||||
boost::optional<std::string> m_device_path;
|
||||
boost::optional<std::string> m_session;
|
||||
boost::optional<std::string> m_response;
|
||||
boost::optional<epee::wipeable_string> m_response;
|
||||
boost::optional<json> m_device_info;
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "byte_slice.h"
|
||||
|
||||
namespace net
|
||||
{
|
||||
namespace zmq
|
||||
|
@ -183,6 +185,22 @@ namespace zmq
|
|||
{
|
||||
return retry_op(zmq_send, socket, payload.data(), payload.size(), flags);
|
||||
}
|
||||
|
||||
expect<void> send(epee::byte_slice&& payload, void* socket, int flags) noexcept
|
||||
{
|
||||
void* const data = const_cast<std::uint8_t*>(payload.data());
|
||||
const std::size_t size = payload.size();
|
||||
auto buffer = payload.take_buffer(); // clears `payload` from callee
|
||||
|
||||
zmq_msg_t msg{};
|
||||
MONERO_ZMQ_CHECK(zmq_msg_init_data(std::addressof(msg), data, size, epee::release_byte_slice::call, buffer.get()));
|
||||
buffer.release(); // zmq will now decrement byte_slice ref-count
|
||||
|
||||
expect<void> sent = retry_op(zmq_msg_send, std::addressof(msg), socket, flags);
|
||||
if (!sent) // beware if removing `noexcept` from this function - possible leak here
|
||||
zmq_msg_close(std::addressof(msg));
|
||||
return sent;
|
||||
}
|
||||
} // zmq
|
||||
} // net
|
||||
|
||||
|
|
|
@ -53,6 +53,11 @@
|
|||
#define MONERO_ZMQ_THROW(msg) \
|
||||
MONERO_THROW( ::net::zmq::get_error_code(), msg )
|
||||
|
||||
namespace epee
|
||||
{
|
||||
class byte_slice;
|
||||
}
|
||||
|
||||
namespace net
|
||||
{
|
||||
namespace zmq
|
||||
|
@ -132,5 +137,24 @@ namespace zmq
|
|||
\param flags See `zmq_send` for possible flags.
|
||||
\return `success()` if sent, otherwise ZMQ error. */
|
||||
expect<void> send(epee::span<const std::uint8_t> payload, void* socket, int flags = 0) noexcept;
|
||||
|
||||
/*! Sends `payload` on `socket`. Blocks until the entire message is queued
|
||||
for sending, or until `zmq_term` is called on the `zmq_context`
|
||||
associated with `socket`. If the context is terminated,
|
||||
`make_error_code(ETERM)` is returned.
|
||||
|
||||
\note This will automatically retry on `EINTR`, so exiting on
|
||||
interrupts requires context termination.
|
||||
\note If non-blocking behavior is requested on `socket` or by `flags`,
|
||||
then `net::zmq::make_error_code(EAGAIN)` will be returned if this
|
||||
would block.
|
||||
|
||||
\param payload sent as one message on `socket`.
|
||||
\param socket Handle created with `zmq_socket`.
|
||||
\param flags See `zmq_msg_send` for possible flags.
|
||||
|
||||
\post `payload.emtpy()` - ownership is transferred to zmq.
|
||||
\return `success()` if sent, otherwise ZMQ error. */
|
||||
expect<void> send(epee::byte_slice&& payload, void* socket, int flags = 0) noexcept;
|
||||
} // zmq
|
||||
} // net
|
||||
|
|
|
@ -905,7 +905,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
|
|||
rct::key m_y0 = rct::zero(), y1 = rct::zero();
|
||||
int proof_data_index = 0;
|
||||
rct::keyV w_cache;
|
||||
rct::keyV proof8_V, proof8_L, proof8_R;
|
||||
std::vector<ge_p3> proof8_V, proof8_L, proof8_R;
|
||||
for (const Bulletproof *p: proofs)
|
||||
{
|
||||
const Bulletproof &proof = *p;
|
||||
|
@ -918,13 +918,17 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
|
|||
const rct::key weight_z = rct::skGen();
|
||||
|
||||
// pre-multiply some points by 8
|
||||
proof8_V.resize(proof.V.size()); for (size_t i = 0; i < proof.V.size(); ++i) proof8_V[i] = rct::scalarmult8(proof.V[i]);
|
||||
proof8_L.resize(proof.L.size()); for (size_t i = 0; i < proof.L.size(); ++i) proof8_L[i] = rct::scalarmult8(proof.L[i]);
|
||||
proof8_R.resize(proof.R.size()); for (size_t i = 0; i < proof.R.size(); ++i) proof8_R[i] = rct::scalarmult8(proof.R[i]);
|
||||
rct::key proof8_T1 = rct::scalarmult8(proof.T1);
|
||||
rct::key proof8_T2 = rct::scalarmult8(proof.T2);
|
||||
rct::key proof8_S = rct::scalarmult8(proof.S);
|
||||
rct::key proof8_A = rct::scalarmult8(proof.A);
|
||||
proof8_V.resize(proof.V.size()); for (size_t i = 0; i < proof.V.size(); ++i) rct::scalarmult8(proof8_V[i], proof.V[i]);
|
||||
proof8_L.resize(proof.L.size()); for (size_t i = 0; i < proof.L.size(); ++i) rct::scalarmult8(proof8_L[i], proof.L[i]);
|
||||
proof8_R.resize(proof.R.size()); for (size_t i = 0; i < proof.R.size(); ++i) rct::scalarmult8(proof8_R[i], proof.R[i]);
|
||||
ge_p3 proof8_T1;
|
||||
ge_p3 proof8_T2;
|
||||
ge_p3 proof8_S;
|
||||
ge_p3 proof8_A;
|
||||
rct::scalarmult8(proof8_T1, proof.T1);
|
||||
rct::scalarmult8(proof8_T2, proof.T2);
|
||||
rct::scalarmult8(proof8_S, proof.S);
|
||||
rct::scalarmult8(proof8_A, proof.A);
|
||||
|
||||
PERF_TIMER_START_BP(VERIFY_line_61);
|
||||
sc_mulsub(m_y0.bytes, proof.taux.bytes, weight_y.bytes, m_y0.bytes);
|
||||
|
|
|
@ -408,6 +408,18 @@ namespace rct {
|
|||
return res;
|
||||
}
|
||||
|
||||
//Computes 8P without byte conversion
|
||||
void scalarmult8(ge_p3 &res, const key &P)
|
||||
{
|
||||
ge_p3 p3;
|
||||
CHECK_AND_ASSERT_THROW_MES_L1(ge_frombytes_vartime(&p3, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
|
||||
ge_p2 p2;
|
||||
ge_p3_to_p2(&p2, &p3);
|
||||
ge_p1p1 p1;
|
||||
ge_mul8(&p1, &p2);
|
||||
ge_p1p1_to_p3(&res, &p1);
|
||||
}
|
||||
|
||||
//Computes lA where l is the curve order
|
||||
bool isInMainSubgroup(const key & A) {
|
||||
ge_p3 p3;
|
||||
|
|
|
@ -124,6 +124,7 @@ namespace rct {
|
|||
key scalarmultH(const key & a);
|
||||
// multiplies a point by 8
|
||||
key scalarmult8(const key & P);
|
||||
void scalarmult8(ge_p3 &res, const key & P);
|
||||
// checks a is in the main subgroup (ie, not a small one)
|
||||
bool isInMainSubgroup(const key & a);
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ namespace bootstrap_node
|
|||
|
||||
struct selector
|
||||
{
|
||||
virtual ~selector() = default;
|
||||
|
||||
virtual void handle_result(const std::string &address, bool success) = 0;
|
||||
virtual boost::optional<node_info> next_node() = 0;
|
||||
};
|
||||
|
|
|
@ -224,7 +224,7 @@ namespace cryptonote
|
|||
}
|
||||
else if (address == "auto")
|
||||
{
|
||||
auto get_nodes = [this, credits_per_hash_threshold]() {
|
||||
auto get_nodes = [this]() {
|
||||
return get_public_nodes(credits_per_hash_threshold);
|
||||
};
|
||||
m_bootstrap_daemon.reset(new bootstrap_daemon(std::move(get_nodes), rpc_payment_enabled));
|
||||
|
@ -438,7 +438,7 @@ namespace cryptonote
|
|||
store_difficulty(m_core.get_blockchain_storage().get_difficulty_for_next_block(), res.difficulty, res.wide_difficulty, res.difficulty_top64);
|
||||
res.target = m_core.get_blockchain_storage().get_difficulty_target();
|
||||
res.tx_count = m_core.get_blockchain_storage().get_total_transactions() - res.height; //without coinbase
|
||||
res.tx_pool_size = m_core.get_pool_transactions_count();
|
||||
res.tx_pool_size = m_core.get_pool_transactions_count(!restricted);
|
||||
res.alt_blocks_count = restricted ? 0 : m_core.get_blockchain_storage().get_alternative_blocks_count();
|
||||
uint64_t total_conn = restricted ? 0 : m_p2p.get_public_connections_count();
|
||||
res.outgoing_connections_count = restricted ? 0 : m_p2p.get_public_outgoing_connections_count();
|
||||
|
@ -1119,6 +1119,8 @@ namespace cryptonote
|
|||
}
|
||||
res.sanity_check_failed = false;
|
||||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
|
||||
tx_verification_context tvc{};
|
||||
if(!m_core.handle_incoming_tx({tx_blob, crypto::null_hash}, tvc, (req.do_not_relay ? relay_method::none : relay_method::local), false) || tvc.m_verifivation_failed)
|
||||
{
|
||||
|
@ -1423,12 +1425,13 @@ namespace cryptonote
|
|||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
const bool request_has_rpc_origin = ctx != NULL;
|
||||
const bool allow_sensitive = !request_has_rpc_origin || !restricted;
|
||||
|
||||
size_t n_txes = m_core.get_pool_transactions_count();
|
||||
size_t n_txes = m_core.get_pool_transactions_count(allow_sensitive);
|
||||
if (n_txes > 0)
|
||||
{
|
||||
CHECK_PAYMENT_SAME_TS(req, res, n_txes * COST_PER_TX);
|
||||
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !restricted);
|
||||
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, allow_sensitive);
|
||||
for (tx_info& txi : res.transactions)
|
||||
txi.tx_blob = epee::string_tools::buff_to_hex_nodelimer(txi.tx_blob);
|
||||
}
|
||||
|
@ -1448,12 +1451,13 @@ namespace cryptonote
|
|||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
const bool request_has_rpc_origin = ctx != NULL;
|
||||
const bool allow_sensitive = !request_has_rpc_origin || !restricted;
|
||||
|
||||
size_t n_txes = m_core.get_pool_transactions_count();
|
||||
size_t n_txes = m_core.get_pool_transactions_count(allow_sensitive);
|
||||
if (n_txes > 0)
|
||||
{
|
||||
CHECK_PAYMENT_SAME_TS(req, res, n_txes * COST_PER_POOL_HASH);
|
||||
m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !restricted);
|
||||
m_core.get_pool_transaction_hashes(res.tx_hashes, allow_sensitive);
|
||||
}
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
|
@ -1471,13 +1475,14 @@ namespace cryptonote
|
|||
|
||||
const bool restricted = m_restricted && ctx;
|
||||
const bool request_has_rpc_origin = ctx != NULL;
|
||||
const bool allow_sensitive = !request_has_rpc_origin || !restricted;
|
||||
|
||||
size_t n_txes = m_core.get_pool_transactions_count();
|
||||
size_t n_txes = m_core.get_pool_transactions_count(allow_sensitive);
|
||||
if (n_txes > 0)
|
||||
{
|
||||
CHECK_PAYMENT_SAME_TS(req, res, n_txes * COST_PER_POOL_HASH);
|
||||
std::vector<crypto::hash> tx_hashes;
|
||||
m_core.get_pool_transaction_hashes(tx_hashes, !request_has_rpc_origin || !restricted);
|
||||
m_core.get_pool_transaction_hashes(tx_hashes, allow_sensitive);
|
||||
res.tx_hashes.reserve(tx_hashes.size());
|
||||
for (const crypto::hash &tx_hash: tx_hashes)
|
||||
res.tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash));
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <stdexcept>
|
||||
|
||||
#include <boost/uuid/nil_generator.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
// likely included by daemon_handler.h's includes,
|
||||
// but including here for clarity
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
|
@ -48,7 +49,7 @@ namespace rpc
|
|||
{
|
||||
namespace
|
||||
{
|
||||
using handler_function = std::string(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& msg);
|
||||
using handler_function = epee::byte_slice(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& msg);
|
||||
struct handler_map
|
||||
{
|
||||
const char* method_name;
|
||||
|
@ -66,7 +67,7 @@ namespace rpc
|
|||
}
|
||||
|
||||
template<typename Message>
|
||||
std::string handle_message(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& parameters)
|
||||
epee::byte_slice handle_message(DaemonHandler& handler, const rapidjson::Value& id, const rapidjson::Value& parameters)
|
||||
{
|
||||
typename Message::Request request{};
|
||||
request.fromJson(parameters);
|
||||
|
@ -903,7 +904,7 @@ namespace rpc
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string DaemonHandler::handle(const std::string& request)
|
||||
epee::byte_slice DaemonHandler::handle(const std::string& request)
|
||||
{
|
||||
MDEBUG("Handling RPC request: " << request);
|
||||
|
||||
|
@ -916,8 +917,11 @@ namespace rpc
|
|||
if (matched_handler == std::end(handlers) || matched_handler->method_name != request_type)
|
||||
return BAD_REQUEST(request_type, req_full.getID());
|
||||
|
||||
std::string response = matched_handler->call(*this, req_full.getID(), req_full.getMessage());
|
||||
MDEBUG("Returning RPC response: " << response);
|
||||
epee::byte_slice response = matched_handler->call(*this, req_full.getID(), req_full.getMessage());
|
||||
|
||||
const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
|
||||
MDEBUG("Returning RPC response: " << response_view);
|
||||
|
||||
return response;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "byte_slice.h"
|
||||
#include "daemon_messages.h"
|
||||
#include "daemon_rpc_version.h"
|
||||
#include "rpc_handler.h"
|
||||
|
@ -132,7 +133,7 @@ class DaemonHandler : public RpcHandler
|
|||
|
||||
void handle(const GetOutputDistribution::Request& req, GetOutputDistribution::Response& res);
|
||||
|
||||
std::string handle(const std::string& request);
|
||||
epee::byte_slice handle(const std::string& request) override final;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ cryptonote::rpc::error FullMessage::getError()
|
|||
return err;
|
||||
}
|
||||
|
||||
std::string FullMessage::getRequest(const std::string& request, const Message& message, const unsigned id)
|
||||
epee::byte_slice FullMessage::getRequest(const std::string& request, const Message& message, const unsigned id)
|
||||
{
|
||||
rapidjson::StringBuffer buffer;
|
||||
{
|
||||
|
@ -172,11 +172,11 @@ std::string FullMessage::getRequest(const std::string& request, const Message& m
|
|||
if (!dest.IsComplete())
|
||||
throw std::logic_error{"Invalid JSON tree generated"};
|
||||
}
|
||||
return std::string{buffer.GetString(), buffer.GetSize()};
|
||||
return epee::byte_slice{{buffer.GetString(), buffer.GetSize()}};
|
||||
}
|
||||
|
||||
|
||||
std::string FullMessage::getResponse(const Message& message, const rapidjson::Value& id)
|
||||
epee::byte_slice FullMessage::getResponse(const Message& message, const rapidjson::Value& id)
|
||||
{
|
||||
rapidjson::StringBuffer buffer;
|
||||
{
|
||||
|
@ -207,17 +207,17 @@ std::string FullMessage::getResponse(const Message& message, const rapidjson::Va
|
|||
if (!dest.IsComplete())
|
||||
throw std::logic_error{"Invalid JSON tree generated"};
|
||||
}
|
||||
return std::string{buffer.GetString(), buffer.GetSize()};
|
||||
return epee::byte_slice{{buffer.GetString(), buffer.GetSize()}};
|
||||
}
|
||||
|
||||
// convenience functions for bad input
|
||||
std::string BAD_REQUEST(const std::string& request)
|
||||
epee::byte_slice BAD_REQUEST(const std::string& request)
|
||||
{
|
||||
rapidjson::Value invalid;
|
||||
return BAD_REQUEST(request, invalid);
|
||||
}
|
||||
|
||||
std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id)
|
||||
epee::byte_slice BAD_REQUEST(const std::string& request, const rapidjson::Value& id)
|
||||
{
|
||||
Message fail;
|
||||
fail.status = Message::STATUS_BAD_REQUEST;
|
||||
|
@ -225,7 +225,7 @@ std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id)
|
|||
return FullMessage::getResponse(fail, id);
|
||||
}
|
||||
|
||||
std::string BAD_JSON(const std::string& error_details)
|
||||
epee::byte_slice BAD_JSON(const std::string& error_details)
|
||||
{
|
||||
rapidjson::Value invalid;
|
||||
Message fail;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <rapidjson/writer.h>
|
||||
#include <string>
|
||||
|
||||
#include "byte_slice.h"
|
||||
#include "rpc/message_data_structs.h"
|
||||
|
||||
namespace cryptonote
|
||||
|
@ -85,8 +86,8 @@ namespace rpc
|
|||
|
||||
cryptonote::rpc::error getError();
|
||||
|
||||
static std::string getRequest(const std::string& request, const Message& message, unsigned id);
|
||||
static std::string getResponse(const Message& message, const rapidjson::Value& id);
|
||||
static epee::byte_slice getRequest(const std::string& request, const Message& message, unsigned id);
|
||||
static epee::byte_slice getResponse(const Message& message, const rapidjson::Value& id);
|
||||
private:
|
||||
|
||||
FullMessage() = default;
|
||||
|
@ -99,10 +100,10 @@ namespace rpc
|
|||
|
||||
|
||||
// convenience functions for bad input
|
||||
std::string BAD_REQUEST(const std::string& request);
|
||||
std::string BAD_REQUEST(const std::string& request, const rapidjson::Value& id);
|
||||
epee::byte_slice BAD_REQUEST(const std::string& request);
|
||||
epee::byte_slice BAD_REQUEST(const std::string& request, const rapidjson::Value& id);
|
||||
|
||||
std::string BAD_JSON(const std::string& error_details);
|
||||
epee::byte_slice BAD_JSON(const std::string& error_details);
|
||||
|
||||
|
||||
} // namespace rpc
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "byte_slice.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
namespace cryptonote
|
||||
|
@ -54,7 +55,7 @@ class RpcHandler
|
|||
RpcHandler() { }
|
||||
virtual ~RpcHandler() { }
|
||||
|
||||
virtual std::string handle(const std::string& request) = 0;
|
||||
virtual epee::byte_slice handle(const std::string& request) = 0;
|
||||
|
||||
static boost::optional<output_distribution_data>
|
||||
get_output_distribution(const std::function<bool(uint64_t, uint64_t, uint64_t, uint64_t&, std::vector<uint64_t>&, uint64_t&)> &f, uint64_t amount, uint64_t from_height, uint64_t to_height, const std::function<crypto::hash(uint64_t)> &get_hash, bool cumulative, uint64_t blockchain_height);
|
||||
|
|
|
@ -28,10 +28,13 @@
|
|||
|
||||
#include "zmq_server.h"
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <system_error>
|
||||
|
||||
#include "byte_slice.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
|
@ -73,10 +76,11 @@ void ZmqServer::serve()
|
|||
{
|
||||
const std::string message = MONERO_UNWRAP(net::zmq::receive(socket.get()));
|
||||
MDEBUG("Received RPC request: \"" << message << "\"");
|
||||
const std::string& response = handler.handle(message);
|
||||
epee::byte_slice response = handler.handle(message);
|
||||
|
||||
MONERO_UNWRAP(net::zmq::send(epee::strspan<std::uint8_t>(response), socket.get()));
|
||||
MDEBUG("Sent RPC reply: \"" << response << "\"");
|
||||
const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
|
||||
MDEBUG("Sending RPC reply: \"" << response_view << "\"");
|
||||
MONERO_UNWRAP(net::zmq::send(std::move(response), socket.get()));
|
||||
}
|
||||
}
|
||||
catch (const std::system_error& e)
|
||||
|
|
|
@ -182,6 +182,7 @@ namespace
|
|||
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_SWEEP_ACCOUNT("sweep_account <account> [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id (obsolete)>]");
|
||||
|
@ -207,7 +208,7 @@ namespace
|
|||
const char* USAGE_CHECK_SPEND_PROOF("check_spend_proof <txid> <signature_file> [<message>]");
|
||||
const char* USAGE_GET_RESERVE_PROOF("get_reserve_proof (all|<amount>) [<message>]");
|
||||
const char* USAGE_CHECK_RESERVE_PROOF("check_reserve_proof <address> <signature_file> [<message>]");
|
||||
const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
|
||||
const char* USAGE_SHOW_TRANSFERS("show_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
|
||||
const char* USAGE_UNSPENT_OUTPUTS("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]");
|
||||
const char* USAGE_RESCAN_BC("rescan_bc [hard|soft|keep_ki] [start_height=0]");
|
||||
const char* USAGE_SET_TX_NOTE("set_tx_note <txid> [free text note]");
|
||||
|
@ -3145,6 +3146,9 @@ simple_wallet::simple_wallet()
|
|||
m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1),
|
||||
tr(USAGE_SWEEP_ALL),
|
||||
tr("Send all unlocked balance to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
|
||||
m_cmd_binder.set_handler("sweep_account", boost::bind(&simple_wallet::sweep_account, this, _1),
|
||||
tr(USAGE_SWEEP_ACCOUNT),
|
||||
tr("Send all unlocked balance from a given account to an address. If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
|
||||
m_cmd_binder.set_handler("sweep_below",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_below, _1),
|
||||
tr(USAGE_SWEEP_BELOW),
|
||||
|
@ -3338,7 +3342,7 @@ simple_wallet::simple_wallet()
|
|||
"** Set of address indices used as inputs in this transfer."));
|
||||
m_cmd_binder.set_handler("export_transfers",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::export_transfers, _1),
|
||||
tr("export_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<filepath>]"),
|
||||
tr("export_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<filepath>]"),
|
||||
tr("Export to CSV the incoming/outgoing transfers within an optional height range."));
|
||||
m_cmd_binder.set_handler("unspent_outputs",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::unspent_outputs, _1),
|
||||
|
@ -5576,14 +5580,19 @@ boost::optional<epee::wipeable_string> simple_wallet::on_device_pin_request()
|
|||
return pwd_container->password();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
boost::optional<epee::wipeable_string> simple_wallet::on_device_passphrase_request(bool on_device)
|
||||
boost::optional<epee::wipeable_string> simple_wallet::on_device_passphrase_request(bool & on_device)
|
||||
{
|
||||
if (on_device) {
|
||||
std::string accepted = input_line(tr(
|
||||
"Device asks for passphrase. Do you want to enter the passphrase on device (Y) (or on the host (N))?"));
|
||||
if (std::cin.eof() || command_line::is_yes(accepted)) {
|
||||
message_writer(console_color_white, true) << tr("Please enter the device passphrase on the device");
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
PAUSE_READLINE();
|
||||
on_device = false;
|
||||
std::string msg = tr("Enter device passphrase");
|
||||
auto pwd_container = tools::password_container::prompt(false, msg.c_str());
|
||||
THROW_WALLET_EXCEPTION_IF(!pwd_container, tools::error::password_entry_failed, tr("Failed to read device passphrase"));
|
||||
|
@ -6221,6 +6230,7 @@ bool simple_wallet::prompt_if_old(const std::vector<tools::wallet2::pending_tx>
|
|||
}
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void simple_wallet::check_for_inactivity_lock(bool user)
|
||||
{
|
||||
if (m_locked)
|
||||
|
@ -6758,7 +6768,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_)
|
||||
{
|
||||
sweep_main(0, true, args_);
|
||||
sweep_main(m_current_subaddress_account, 0, true, args_);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -6869,18 +6879,22 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
|||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args_)
|
||||
bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_)
|
||||
{
|
||||
auto print_usage = [below]()
|
||||
auto print_usage = [this, account, below]()
|
||||
{
|
||||
if (below)
|
||||
{
|
||||
PRINT_USAGE(USAGE_SWEEP_BELOW);
|
||||
}
|
||||
else
|
||||
else if (account == m_current_subaddress_account)
|
||||
{
|
||||
PRINT_USAGE(USAGE_SWEEP_ALL);
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_USAGE(USAGE_SWEEP_ACCOUNT);
|
||||
}
|
||||
};
|
||||
if (args_.size() == 0)
|
||||
{
|
||||
|
@ -7054,7 +7068,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
|
|||
try
|
||||
{
|
||||
// figure out what tx will be necessary
|
||||
auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
|
||||
auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, account, subaddr_indices);
|
||||
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
|
@ -7394,7 +7408,27 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_all(const std::vector<std::string> &args_)
|
||||
{
|
||||
sweep_main(0, false, args_);
|
||||
sweep_main(m_current_subaddress_account, 0, false, args_);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::sweep_account(const std::vector<std::string> &args_)
|
||||
{
|
||||
auto local_args = args_;
|
||||
if (local_args.empty())
|
||||
{
|
||||
PRINT_USAGE(USAGE_SWEEP_ACCOUNT);
|
||||
return true;
|
||||
}
|
||||
uint32_t account = 0;
|
||||
if (!epee::string_tools::get_xtype_from_string(account, local_args[0]))
|
||||
{
|
||||
fail_msg_writer() << tr("Invalid account");
|
||||
return true;
|
||||
}
|
||||
local_args.erase(local_args.begin());
|
||||
|
||||
sweep_main(account, 0, false, local_args);
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -7411,7 +7445,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
|
|||
fail_msg_writer() << tr("invalid amount threshold");
|
||||
return true;
|
||||
}
|
||||
sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end()));
|
||||
sweep_main(m_current_subaddress_account, below, false, std::vector<std::string>(++args_.begin(), args_.end()));
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -8508,7 +8542,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
|
|||
std::vector<std::string> local_args = args_;
|
||||
|
||||
if(local_args.size() > 4) {
|
||||
fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
|
||||
fail_msg_writer() << tr("usage: show_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -8561,7 +8595,7 @@ bool simple_wallet::export_transfers(const std::vector<std::string>& args_)
|
|||
std::vector<std::string> local_args = args_;
|
||||
|
||||
if(local_args.size() > 5) {
|
||||
fail_msg_writer() << tr("usage: export_transfers [in|out|all|pending|failed|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<path>]");
|
||||
fail_msg_writer() << tr("usage: export_transfers [in|out|all|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]] [output=<path>]");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -170,8 +170,9 @@ namespace cryptonote
|
|||
bool transfer(const std::vector<std::string> &args);
|
||||
bool locked_transfer(const std::vector<std::string> &args);
|
||||
bool locked_sweep_all(const std::vector<std::string> &args);
|
||||
bool sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args);
|
||||
bool sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args);
|
||||
bool sweep_all(const std::vector<std::string> &args);
|
||||
bool sweep_account(const std::vector<std::string> &args);
|
||||
bool sweep_below(const std::vector<std::string> &args);
|
||||
bool sweep_single(const std::vector<std::string> &args);
|
||||
bool sweep_unmixable(const std::vector<std::string> &args);
|
||||
|
@ -348,7 +349,7 @@ namespace cryptonote
|
|||
virtual boost::optional<epee::wipeable_string> on_get_password(const char *reason);
|
||||
virtual void on_device_button_request(uint64_t code);
|
||||
virtual boost::optional<epee::wipeable_string> on_device_pin_request();
|
||||
virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device);
|
||||
virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device);
|
||||
//----------------------------------------------------------
|
||||
|
||||
friend class refresh_progress_reporter_t;
|
||||
|
|
|
@ -267,13 +267,15 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
|||
return boost::none;
|
||||
}
|
||||
|
||||
virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device)
|
||||
virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device)
|
||||
{
|
||||
if (m_listener) {
|
||||
auto passphrase = m_listener->onDevicePassphraseRequest(on_device);
|
||||
if (!on_device && passphrase) {
|
||||
if (passphrase) {
|
||||
return boost::make_optional(epee::wipeable_string((*passphrase).data(), (*passphrase).size()));
|
||||
}
|
||||
} else {
|
||||
on_device = true;
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
|
|
@ -400,8 +400,8 @@ struct WalletListener
|
|||
/**
|
||||
* @brief called by device when passphrase entry is needed
|
||||
*/
|
||||
virtual optional<std::string> onDevicePassphraseRequest(bool on_device) {
|
||||
if (!on_device) throw std::runtime_error("Not supported");
|
||||
virtual optional<std::string> onDevicePassphraseRequest(bool & on_device) {
|
||||
on_device = true;
|
||||
return optional<std::string>();
|
||||
}
|
||||
|
||||
|
@ -1293,7 +1293,11 @@ struct WalletManager
|
|||
virtual std::string resolveOpenAlias(const std::string &address, bool &dnssec_valid) const = 0;
|
||||
|
||||
//! checks for an update and returns version, hash and url
|
||||
static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(const std::string &software, std::string subdir);
|
||||
static std::tuple<bool, std::string, std::string, std::string, std::string> checkUpdates(
|
||||
const std::string &software,
|
||||
std::string subdir,
|
||||
const char *buildtag = nullptr,
|
||||
const char *current_version = nullptr);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -342,22 +342,30 @@ std::string WalletManagerImpl::resolveOpenAlias(const std::string &address, bool
|
|||
return addresses.front();
|
||||
}
|
||||
|
||||
std::tuple<bool, std::string, std::string, std::string, std::string> WalletManager::checkUpdates(const std::string &software, std::string subdir)
|
||||
std::tuple<bool, std::string, std::string, std::string, std::string> WalletManager::checkUpdates(
|
||||
const std::string &software,
|
||||
std::string subdir,
|
||||
const char *buildtag/* = nullptr*/,
|
||||
const char *current_version/* = nullptr*/)
|
||||
{
|
||||
if (buildtag == nullptr)
|
||||
{
|
||||
#ifdef BUILD_TAG
|
||||
static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG);
|
||||
static const char buildtag_default[] = BOOST_PP_STRINGIZE(BUILD_TAG);
|
||||
#else
|
||||
static const char buildtag[] = "source";
|
||||
static const char buildtag_default[] = "source";
|
||||
// Override the subdir string when built from source
|
||||
subdir = "source";
|
||||
#endif
|
||||
buildtag = buildtag_default;
|
||||
}
|
||||
|
||||
std::string version, hash;
|
||||
MDEBUG("Checking for a new " << software << " version for " << buildtag);
|
||||
if (!tools::check_updates(software, buildtag, version, hash))
|
||||
return std::make_tuple(false, "", "", "", "");
|
||||
|
||||
if (tools::vercmp(version.c_str(), MONERO_VERSION) > 0)
|
||||
if (tools::vercmp(version.c_str(), current_version != nullptr ? current_version : MONERO_VERSION) > 0)
|
||||
{
|
||||
std::string user_url = tools::get_update_url(software, subdir, buildtag, version, true);
|
||||
std::string auto_url = tools::get_update_url(software, subdir, buildtag, version, false);
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
namespace mms
|
||||
{
|
||||
|
||||
message_store::message_store()
|
||||
message_store::message_store(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client) : m_transporter(std::move(http_client))
|
||||
{
|
||||
m_active = false;
|
||||
m_auto_send = false;
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "common/i18n.h"
|
||||
#include "common/command_line.h"
|
||||
#include "wipeable_string.h"
|
||||
#include "net/abstract_http_client.h"
|
||||
#include "message_transporter.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
|
@ -202,7 +203,8 @@ namespace mms
|
|||
class message_store
|
||||
{
|
||||
public:
|
||||
message_store();
|
||||
message_store(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client);
|
||||
|
||||
// Initialize and start to use the MMS, set the first signer, this wallet itself
|
||||
// Filename, if not null and not empty, is used to create the ".mms" file
|
||||
// reset it if already used, with deletion of all signers and messages
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace bitmessage_rpc
|
|||
|
||||
}
|
||||
|
||||
message_transporter::message_transporter()
|
||||
message_transporter::message_transporter(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client) : m_http_client(std::move(http_client))
|
||||
{
|
||||
m_run = true;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ void message_transporter::set_options(const std::string &bitmessage_address, con
|
|||
}
|
||||
m_bitmessage_login = bitmessage_login;
|
||||
|
||||
m_http_client.set_server(address_parts.host, std::to_string(address_parts.port), boost::none);
|
||||
m_http_client->set_server(address_parts.host, std::to_string(address_parts.port), boost::none);
|
||||
}
|
||||
|
||||
bool message_transporter::receive_messages(const std::vector<std::string> &destination_transport_addresses,
|
||||
|
@ -256,7 +256,7 @@ bool message_transporter::post_request(const std::string &request, std::string &
|
|||
additional_params.push_back(std::make_pair("Content-Type", "application/xml; charset=utf-8"));
|
||||
const epee::net_utils::http::http_response_info* response = NULL;
|
||||
std::chrono::milliseconds timeout = std::chrono::seconds(15);
|
||||
bool r = m_http_client.invoke("/", "POST", request, timeout, std::addressof(response), std::move(additional_params));
|
||||
bool r = m_http_client->invoke("/", "POST", request, timeout, std::addressof(response), std::move(additional_params));
|
||||
if (r)
|
||||
{
|
||||
answer = response->m_body;
|
||||
|
@ -266,7 +266,7 @@ bool message_transporter::post_request(const std::string &request, std::string &
|
|||
LOG_ERROR("POST request to Bitmessage failed: " << request.substr(0, 300));
|
||||
THROW_WALLET_EXCEPTION(tools::error::no_connection_to_bitmessage, m_bitmessage_url);
|
||||
}
|
||||
m_http_client.disconnect(); // see comment above
|
||||
m_http_client->disconnect(); // see comment above
|
||||
std::string string_value = get_str_between_tags(answer, "<string>", "</string>");
|
||||
if ((string_value.find("API Error") == 0) || (string_value.find("RPC ") == 0))
|
||||
{
|
||||
|
|
|
@ -34,9 +34,9 @@
|
|||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "net/http_server_impl_base.h"
|
||||
#include "net/http_client.h"
|
||||
#include "net/abstract_http_client.h"
|
||||
#include "common/util.h"
|
||||
#include "wipeable_string.h"
|
||||
#include "serialization/keyvalue_serialization.h"
|
||||
#include <vector>
|
||||
|
||||
namespace mms
|
||||
|
@ -83,7 +83,7 @@ typedef epee::misc_utils::struct_init<transport_message_t> transport_message;
|
|||
class message_transporter
|
||||
{
|
||||
public:
|
||||
message_transporter();
|
||||
message_transporter(std::unique_ptr<epee::net_utils::http::abstract_http_client> http_client);
|
||||
void set_options(const std::string &bitmessage_address, const epee::wipeable_string &bitmessage_login);
|
||||
bool send_message(const transport_message &message);
|
||||
bool receive_messages(const std::vector<std::string> &destination_transport_addresses,
|
||||
|
@ -94,7 +94,7 @@ public:
|
|||
bool delete_transport_address(const std::string &transport_address);
|
||||
|
||||
private:
|
||||
epee::net_utils::http::http_simple_client m_http_client;
|
||||
const std::unique_ptr<epee::net_utils::http::abstract_http_client> m_http_client;
|
||||
std::string m_bitmessage_url;
|
||||
epee::wipeable_string m_bitmessage_login;
|
||||
std::atomic<bool> m_run;
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace tools
|
|||
|
||||
static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
|
||||
|
||||
NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex)
|
||||
NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::abstract_http_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex)
|
||||
: m_http_client(http_client)
|
||||
, m_rpc_payment_state(rpc_payment_state)
|
||||
, m_daemon_rpc_mutex(mutex)
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#include <string>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "include_base_utils.h"
|
||||
#include "net/http_client.h"
|
||||
#include "net/abstract_http_client.h"
|
||||
#include "rpc/core_rpc_server_commands_defs.h"
|
||||
#include "wallet_rpc_helpers.h"
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace tools
|
|||
class NodeRPCProxy
|
||||
{
|
||||
public:
|
||||
NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex);
|
||||
NodeRPCProxy(epee::net_utils::http::abstract_http_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex);
|
||||
|
||||
void set_client_secret_key(const crypto::secret_key &skey) { m_client_id_secret_key = skey; }
|
||||
void invalidate();
|
||||
|
@ -72,7 +72,7 @@ private:
|
|||
private:
|
||||
boost::optional<std::string> get_info();
|
||||
|
||||
epee::net_utils::http::http_simple_client &m_http_client;
|
||||
epee::net_utils::http::abstract_http_client &m_http_client;
|
||||
rpc_payment_state_t &m_rpc_payment_state;
|
||||
boost::recursive_mutex &m_daemon_rpc_mutex;
|
||||
crypto::secret_key m_client_id_secret_key;
|
||||
|
|
|
@ -1109,10 +1109,12 @@ boost::optional<epee::wipeable_string> wallet_device_callback::on_pin_request()
|
|||
return boost::none;
|
||||
}
|
||||
|
||||
boost::optional<epee::wipeable_string> wallet_device_callback::on_passphrase_request(bool on_device)
|
||||
boost::optional<epee::wipeable_string> wallet_device_callback::on_passphrase_request(bool & on_device)
|
||||
{
|
||||
if (wallet)
|
||||
return wallet->on_device_passphrase_request(on_device);
|
||||
else
|
||||
on_device = true;
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
|
@ -1122,7 +1124,8 @@ void wallet_device_callback::on_progress(const hw::device_progress& event)
|
|||
wallet->on_device_progress(event);
|
||||
}
|
||||
|
||||
wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
|
||||
wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory):
|
||||
m_http_client(std::move(http_client_factory->create())),
|
||||
m_multisig_rescan_info(NULL),
|
||||
m_multisig_rescan_k(NULL),
|
||||
m_upper_transaction_weight_limit(0),
|
||||
|
@ -1167,7 +1170,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
|
|||
m_watch_only(false),
|
||||
m_multisig(false),
|
||||
m_multisig_threshold(0),
|
||||
m_node_rpc_proxy(m_http_client, m_rpc_payment_state, m_daemon_rpc_mutex),
|
||||
m_node_rpc_proxy(*m_http_client, m_rpc_payment_state, m_daemon_rpc_mutex),
|
||||
m_account_public_address{crypto::null_pkey, crypto::null_pkey},
|
||||
m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR),
|
||||
m_subaddress_lookahead_minor(SUBADDRESS_LOOKAHEAD_MINOR),
|
||||
|
@ -1178,7 +1181,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
|
|||
m_light_wallet_balance(0),
|
||||
m_light_wallet_unlocked_balance(0),
|
||||
m_original_keys_available(false),
|
||||
m_message_store(),
|
||||
m_message_store(http_client_factory->create()),
|
||||
m_key_device_type(hw::device::device_type::SOFTWARE),
|
||||
m_ring_history_saved(false),
|
||||
m_ringdb(),
|
||||
|
@ -1298,8 +1301,8 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u
|
|||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
|
||||
|
||||
if(m_http_client.is_connected())
|
||||
m_http_client.disconnect();
|
||||
if(m_http_client->is_connected())
|
||||
m_http_client->disconnect();
|
||||
const bool changed = m_daemon_address != daemon_address;
|
||||
m_daemon_address = std::move(daemon_address);
|
||||
m_daemon_login = std::move(daemon_login);
|
||||
|
@ -1313,7 +1316,7 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u
|
|||
|
||||
const std::string address = get_daemon_address();
|
||||
MINFO("setting daemon to " << address);
|
||||
bool ret = m_http_client.set_server(address, get_daemon_login(), std::move(ssl_options));
|
||||
bool ret = m_http_client->set_server(address, get_daemon_login(), std::move(ssl_options));
|
||||
if (ret)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(default_daemon_address_lock);
|
||||
|
@ -1328,7 +1331,12 @@ bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::
|
|||
m_is_initialized = true;
|
||||
m_upper_transaction_weight_limit = upper_transaction_weight_limit;
|
||||
if (proxy != boost::asio::ip::tcp::endpoint{})
|
||||
m_http_client.set_connector(net::socks::connector{std::move(proxy)});
|
||||
{
|
||||
epee::net_utils::http::abstract_http_client* abstract_http_client = m_http_client.get();
|
||||
epee::net_utils::http::http_simple_client* http_simple_client = dynamic_cast<epee::net_utils::http::http_simple_client*>(abstract_http_client);
|
||||
CHECK_AND_ASSERT_MES(http_simple_client != nullptr, false, "http_simple_client must be used to set proxy");
|
||||
http_simple_client->set_connector(net::socks::connector{std::move(proxy)});
|
||||
}
|
||||
return set_daemon(daemon_address, daemon_login, trusted_daemon, std::move(ssl_options));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -2595,7 +2603,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "getblocks.bin", error::get_blocks_error, get_rpc_status(res.status));
|
||||
THROW_WALLET_EXCEPTION_IF(res.blocks.size() != res.output_indices.size(), error::wallet_internal_error,
|
||||
"mismatched blocks (" + boost::lexical_cast<std::string>(res.blocks.size()) + ") and output_indices (" +
|
||||
|
@ -2624,7 +2632,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
req.client = get_client_signature();
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
bool r = net_utils::invoke_http_bin("/gethashes.bin", req, res, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_bin("/gethashes.bin", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "gethashes.bin", error::get_hashes_error, get_rpc_status(res.status));
|
||||
check_rpc_cost("/gethashes.bin", res.credits, pre_call_credits, 1 + res.m_block_ids.size() * COST_PER_BLOCK_HASH);
|
||||
}
|
||||
|
@ -2909,7 +2917,7 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_transaction_pool_hashes.bin", error::get_tx_pool_error);
|
||||
check_rpc_cost("/get_transaction_pool_hashes.bin", res.credits, pre_call_credits, 1 + res.tx_hashes.size() * COST_PER_POOL_HASH);
|
||||
}
|
||||
|
@ -3054,7 +3062,7 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
|
||||
if (r && res.status == CORE_RPC_STATUS_OK)
|
||||
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, res.txs.size() * COST_PER_TX);
|
||||
}
|
||||
|
@ -3540,7 +3548,7 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, m_http_client, rpc_timeout);
|
||||
r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/get_output_distribution.bin");
|
||||
check_rpc_cost("/get_output_distribution.bin", res.credits, pre_call_credits, COST_PER_OUTPUT_DISTRIBUTION_0);
|
||||
}
|
||||
|
@ -3698,6 +3706,30 @@ void wallet2::clear_soft(bool keep_key_images)
|
|||
* \return Whether it was successful.
|
||||
*/
|
||||
bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable_string& password, bool watch_only)
|
||||
{
|
||||
boost::optional<wallet2::keys_file_data> keys_file_data = get_keys_file_data(password, watch_only);
|
||||
CHECK_AND_ASSERT_MES(keys_file_data != boost::none, false, "failed to generate wallet keys data");
|
||||
|
||||
std::string tmp_file_name = keys_file_name + ".new";
|
||||
std::string buf;
|
||||
bool r = ::serialization::dump_binary(keys_file_data.get(), buf);
|
||||
r = r && save_to_file(tmp_file_name, buf);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
|
||||
|
||||
unlock_keys_file();
|
||||
std::error_code e = tools::replace_file(tmp_file_name, keys_file_name);
|
||||
lock_keys_file();
|
||||
|
||||
if (e) {
|
||||
boost::filesystem::remove(tmp_file_name);
|
||||
LOG_ERROR("failed to update wallet keys file " << keys_file_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee::wipeable_string& password, bool watch_only)
|
||||
{
|
||||
std::string account_data;
|
||||
std::string multisig_signers;
|
||||
|
@ -3719,8 +3751,8 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
|
|||
account.encrypt_keys(key);
|
||||
|
||||
bool r = epee::serialization::store_t_to_binary(account, account_data);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet keys");
|
||||
wallet2::keys_file_data keys_file_data = {};
|
||||
CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet keys");
|
||||
boost::optional<wallet2::keys_file_data> keys_file_data = (wallet2::keys_file_data) {};
|
||||
|
||||
// Create a JSON object with "key_data" and "seed_language" as keys.
|
||||
rapidjson::Document json;
|
||||
|
@ -3751,12 +3783,12 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
|
|||
if (m_multisig)
|
||||
{
|
||||
bool r = ::serialization::dump_binary(m_multisig_signers, multisig_signers);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet multisig signers");
|
||||
CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet multisig signers");
|
||||
value.SetString(multisig_signers.c_str(), multisig_signers.length());
|
||||
json.AddMember("multisig_signers", value, json.GetAllocator());
|
||||
|
||||
r = ::serialization::dump_binary(m_multisig_derivations, multisig_derivations);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet multisig derivations");
|
||||
CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet multisig derivations");
|
||||
value.SetString(multisig_derivations.c_str(), multisig_derivations.length());
|
||||
json.AddMember("multisig_derivations", value, json.GetAllocator());
|
||||
|
||||
|
@ -3899,27 +3931,10 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
|
|||
// Encrypt the entire JSON object.
|
||||
std::string cipher;
|
||||
cipher.resize(account_data.size());
|
||||
keys_file_data.iv = crypto::rand<crypto::chacha_iv>();
|
||||
crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.iv, &cipher[0]);
|
||||
keys_file_data.account_data = cipher;
|
||||
|
||||
std::string tmp_file_name = keys_file_name + ".new";
|
||||
std::string buf;
|
||||
r = ::serialization::dump_binary(keys_file_data, buf);
|
||||
r = r && save_to_file(tmp_file_name, buf);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
|
||||
|
||||
unlock_keys_file();
|
||||
std::error_code e = tools::replace_file(tmp_file_name, keys_file_name);
|
||||
lock_keys_file();
|
||||
|
||||
if (e) {
|
||||
boost::filesystem::remove(tmp_file_name);
|
||||
LOG_ERROR("failed to update wallet keys file " << keys_file_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
keys_file_data.get().iv = crypto::rand<crypto::chacha_iv>();
|
||||
crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.get().iv, &cipher[0]);
|
||||
keys_file_data.get().account_data = cipher;
|
||||
return keys_file_data;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::setup_keys(const epee::wipeable_string &password)
|
||||
|
@ -3959,16 +3974,51 @@ void wallet2::change_password(const std::string &filename, const epee::wipeable_
|
|||
*/
|
||||
bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_string& password)
|
||||
{
|
||||
rapidjson::Document json;
|
||||
wallet2::keys_file_data keys_file_data;
|
||||
std::string buf;
|
||||
bool encrypted_secret_keys = false;
|
||||
bool r = load_from_file(keys_file_name, buf);
|
||||
std::string keys_file_buf;
|
||||
bool r = load_from_file(keys_file_name, keys_file_buf);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
|
||||
|
||||
// Load keys from buffer
|
||||
boost::optional<crypto::chacha_key> keys_to_encrypt;
|
||||
try {
|
||||
r = wallet2::load_keys_buf(keys_file_buf, password, keys_to_encrypt);
|
||||
} catch (const std::exception& e) {
|
||||
std::size_t found = string(e.what()).find("failed to deserialize keys buffer");
|
||||
THROW_WALLET_EXCEPTION_IF(found != std::string::npos, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Rewrite with encrypted keys if unencrypted, ignore errors
|
||||
if (r && keys_to_encrypt != boost::none)
|
||||
{
|
||||
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
||||
encrypt_keys(keys_to_encrypt.get());
|
||||
bool saved_ret = store_keys(keys_file_name, password, m_watch_only);
|
||||
if (!saved_ret)
|
||||
{
|
||||
// just moan a bit, but not fatal
|
||||
MERROR("Error saving keys file with encrypted keys, not fatal");
|
||||
}
|
||||
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
||||
decrypt_keys(keys_to_encrypt.get());
|
||||
m_keys_file_locker.reset();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password) {
|
||||
boost::optional<crypto::chacha_key> keys_to_encrypt;
|
||||
return wallet2::load_keys_buf(keys_buf, password, keys_to_encrypt);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password, boost::optional<crypto::chacha_key>& keys_to_encrypt) {
|
||||
|
||||
// Decrypt the contents
|
||||
r = ::serialization::parse_binary(buf, keys_file_data);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
|
||||
rapidjson::Document json;
|
||||
wallet2::keys_file_data keys_file_data;
|
||||
bool encrypted_secret_keys = false;
|
||||
bool r = ::serialization::parse_binary(keys_buf, keys_file_data);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize keys buffer");
|
||||
crypto::chacha_key key;
|
||||
crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
|
||||
std::string account_data;
|
||||
|
@ -4287,18 +4337,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
|
|||
}
|
||||
else
|
||||
{
|
||||
// rewrite with encrypted keys, ignore errors
|
||||
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
||||
encrypt_keys(key);
|
||||
bool saved_ret = store_keys(keys_file_name, password, m_watch_only);
|
||||
if (!saved_ret)
|
||||
{
|
||||
// just moan a bit, but not fatal
|
||||
MERROR("Error saving keys file with encrypted keys, not fatal");
|
||||
}
|
||||
if (m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only)
|
||||
decrypt_keys(key);
|
||||
m_keys_file_locker.reset();
|
||||
keys_to_encrypt = key;
|
||||
}
|
||||
}
|
||||
const cryptonote::account_keys& keys = m_account.get_keys();
|
||||
|
@ -4923,6 +4962,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
|
|||
// re-encrypt keys
|
||||
keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
|
||||
|
||||
if (!m_wallet_file.empty())
|
||||
create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
|
||||
|
||||
setup_new_blockchain();
|
||||
|
@ -5063,7 +5103,9 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor
|
|||
|
||||
++m_multisig_rounds_passed;
|
||||
|
||||
if (!m_wallet_file.empty())
|
||||
create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
|
||||
|
||||
return extra_multisig_info;
|
||||
}
|
||||
|
||||
|
@ -5437,13 +5479,13 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
|
|||
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
|
||||
if(!m_http_client.is_connected(ssl))
|
||||
if(!m_http_client->is_connected(ssl))
|
||||
{
|
||||
m_rpc_version = 0;
|
||||
m_node_rpc_proxy.invalidate();
|
||||
if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
|
||||
if (!m_http_client->connect(std::chrono::milliseconds(timeout)))
|
||||
return false;
|
||||
if(!m_http_client.is_connected(ssl))
|
||||
if(!m_http_client->is_connected(ssl))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -5471,12 +5513,12 @@ void wallet2::set_offline(bool offline)
|
|||
{
|
||||
m_offline = offline;
|
||||
m_node_rpc_proxy.set_offline(offline);
|
||||
m_http_client.set_auto_connect(!offline);
|
||||
m_http_client->set_auto_connect(!offline);
|
||||
if (offline)
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
|
||||
if(m_http_client.is_connected())
|
||||
m_http_client.disconnect();
|
||||
if(m_http_client->is_connected())
|
||||
m_http_client->disconnect();
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -5491,12 +5533,18 @@ void wallet2::generate_chacha_key_from_password(const epee::wipeable_string &pas
|
|||
crypto::generate_chacha_key(pass.data(), pass.size(), key, m_kdf_rounds);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password)
|
||||
void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password, const std::string& keys_buf, const std::string& cache_buf)
|
||||
{
|
||||
clear();
|
||||
prepare_file_names(wallet_);
|
||||
|
||||
// determine if loading from file system or string buffer
|
||||
bool use_fs = !wallet_.empty();
|
||||
THROW_WALLET_EXCEPTION_IF((use_fs && !keys_buf.empty()) || (!use_fs && keys_buf.empty()), error::file_read_error, "must load keys either from file system or from buffer");\
|
||||
|
||||
boost::system::error_code e;
|
||||
if (use_fs)
|
||||
{
|
||||
bool exists = boost::filesystem::exists(m_keys_file, e);
|
||||
THROW_WALLET_EXCEPTION_IF(e || !exists, error::file_not_found, m_keys_file);
|
||||
lock_keys_file();
|
||||
|
@ -5510,29 +5558,38 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
|
|||
}
|
||||
LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype));
|
||||
lock_keys_file();
|
||||
}
|
||||
else if (!load_keys_buf(keys_buf, password))
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, "failed to load keys from buffer");
|
||||
}
|
||||
|
||||
wallet_keys_unlocker unlocker(*this, m_ask_password == AskPasswordToDecrypt && !m_unattended && !m_watch_only, password);
|
||||
|
||||
//keys loaded ok!
|
||||
//try to load wallet file. but even if we failed, it is not big problem
|
||||
if(!boost::filesystem::exists(m_wallet_file, e) || e)
|
||||
if (use_fs && (!boost::filesystem::exists(m_wallet_file, e) || e))
|
||||
{
|
||||
LOG_PRINT_L0("file not found: " << m_wallet_file << ", starting with empty blockchain");
|
||||
m_account_public_address = m_account.get_keys().m_account_address;
|
||||
}
|
||||
else
|
||||
else if (use_fs || !cache_buf.empty())
|
||||
{
|
||||
wallet2::cache_file_data cache_file_data;
|
||||
std::string buf;
|
||||
bool r = load_from_file(m_wallet_file, buf, std::numeric_limits<size_t>::max());
|
||||
std::string cache_file_buf;
|
||||
bool r = true;
|
||||
if (use_fs)
|
||||
{
|
||||
load_from_file(m_wallet_file, cache_file_buf, std::numeric_limits<size_t>::max());
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, m_wallet_file);
|
||||
}
|
||||
|
||||
// try to read it as an encrypted cache
|
||||
try
|
||||
{
|
||||
LOG_PRINT_L1("Trying to decrypt cache data");
|
||||
|
||||
r = ::serialization::parse_binary(buf, cache_file_data);
|
||||
r = ::serialization::parse_binary(use_fs ? cache_file_buf : cache_buf, cache_file_data);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + '\"');
|
||||
std::string cache_data;
|
||||
cache_data.resize(cache_file_data.cache_data.size());
|
||||
|
@ -5569,7 +5626,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
|
|||
catch (...)
|
||||
{
|
||||
LOG_PRINT_L0("Failed to open portable binary, trying unportable");
|
||||
boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
|
||||
if (use_fs) boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
|
||||
std::stringstream iss;
|
||||
iss.str("");
|
||||
iss << cache_data;
|
||||
|
@ -5584,17 +5641,17 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
|
|||
LOG_PRINT_L1("Failed to load encrypted cache, trying unencrypted");
|
||||
try {
|
||||
std::stringstream iss;
|
||||
iss << buf;
|
||||
iss << cache_file_buf;
|
||||
boost::archive::portable_binary_iarchive ar(iss);
|
||||
ar >> *this;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG_PRINT_L0("Failed to open portable binary, trying unportable");
|
||||
boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
|
||||
if (use_fs) boost::filesystem::copy_file(m_wallet_file, m_wallet_file + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
|
||||
std::stringstream iss;
|
||||
iss.str("");
|
||||
iss << buf;
|
||||
iss << cache_file_buf;
|
||||
boost::archive::binary_iarchive ar(iss);
|
||||
ar >> *this;
|
||||
}
|
||||
|
@ -5638,6 +5695,7 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
|
|||
|
||||
try
|
||||
{
|
||||
if (use_fs)
|
||||
m_message_store.read_from_file(get_multisig_wallet_state(), m_mms_file);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
|
@ -5666,7 +5724,7 @@ void wallet2::trim_hashchain()
|
|||
req.height = m_blockchain.size() - 1;
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, m_http_client, rpc_timeout);
|
||||
r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, *m_http_client, rpc_timeout);
|
||||
if (r && res.status == CORE_RPC_STATUS_OK)
|
||||
check_rpc_cost("getblockheaderbyheight", res.credits, pre_call_credits, COST_PER_BLOCK_HEADER);
|
||||
}
|
||||
|
@ -5741,18 +5799,10 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
|||
}
|
||||
}
|
||||
}
|
||||
// preparing wallet data
|
||||
std::stringstream oss;
|
||||
boost::archive::portable_binary_oarchive ar(oss);
|
||||
ar << *this;
|
||||
|
||||
wallet2::cache_file_data cache_file_data = {};
|
||||
cache_file_data.cache_data = oss.str();
|
||||
std::string cipher;
|
||||
cipher.resize(cache_file_data.cache_data.size());
|
||||
cache_file_data.iv = crypto::rand<crypto::chacha_iv>();
|
||||
crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cipher[0]);
|
||||
cache_file_data.cache_data = cipher;
|
||||
// get wallet cache data
|
||||
boost::optional<wallet2::cache_file_data> cache_file_data = get_cache_file_data(password);
|
||||
THROW_WALLET_EXCEPTION_IF(cache_file_data == boost::none, error::wallet_internal_error, "failed to generate wallet cache data");
|
||||
|
||||
const std::string new_file = same_file ? m_wallet_file + ".new" : path;
|
||||
const std::string old_file = m_wallet_file;
|
||||
|
@ -5803,7 +5853,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
|||
// The price to pay is temporary higher memory consumption for string stream + binary archive
|
||||
std::ostringstream oss;
|
||||
binary_archive<true> oar(oss);
|
||||
bool success = ::serialization::serialize(oar, cache_file_data);
|
||||
bool success = ::serialization::serialize(oar, cache_file_data.get());
|
||||
if (success) {
|
||||
success = save_to_file(new_file, oss.str());
|
||||
}
|
||||
|
@ -5812,7 +5862,7 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
|||
std::ofstream ostr;
|
||||
ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||
binary_archive<true> oar(ostr);
|
||||
bool success = ::serialization::serialize(oar, cache_file_data);
|
||||
bool success = ::serialization::serialize(oar, cache_file_data.get());
|
||||
ostr.close();
|
||||
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
|
||||
#endif
|
||||
|
@ -5828,7 +5878,30 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
|
|||
// store should only exist if the MMS is really active
|
||||
m_message_store.write_to_file(get_multisig_wallet_state(), m_mms_file);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
boost::optional<wallet2::cache_file_data> wallet2::get_cache_file_data(const epee::wipeable_string &passwords)
|
||||
{
|
||||
trim_hashchain();
|
||||
try
|
||||
{
|
||||
std::stringstream oss;
|
||||
boost::archive::portable_binary_oarchive ar(oss);
|
||||
ar << *this;
|
||||
|
||||
boost::optional<wallet2::cache_file_data> cache_file_data = (wallet2::cache_file_data) {};
|
||||
cache_file_data.get().cache_data = oss.str();
|
||||
std::string cipher;
|
||||
cipher.resize(cache_file_data.get().cache_data.size());
|
||||
cache_file_data.get().iv = crypto::rand<crypto::chacha_iv>();
|
||||
crypto::chacha20(cache_file_data.get().cache_data.data(), cache_file_data.get().cache_data.size(), m_cache_key, cache_file_data.get().iv, &cipher[0]);
|
||||
cache_file_data.get().cache_data = cipher;
|
||||
return cache_file_data;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::balance(uint32_t index_major, bool strict) const
|
||||
|
@ -6032,7 +6105,7 @@ void wallet2::rescan_spent()
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, daemon_resp, "is_key_image_spent", error::is_key_image_spent_error, get_rpc_status(daemon_resp.status));
|
||||
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != n_outputs, error::wallet_internal_error,
|
||||
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
|
||||
|
@ -6360,7 +6433,7 @@ void wallet2::commit_tx(pending_tx& ptx)
|
|||
oreq.tx = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
|
||||
{
|
||||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
bool r = epee::net_utils::invoke_http_json("/submit_raw_tx", oreq, ores, m_http_client, rpc_timeout, "POST");
|
||||
bool r = epee::net_utils::invoke_http_json("/submit_raw_tx", oreq, ores, *m_http_client, rpc_timeout, "POST");
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "submit_raw_tx");
|
||||
// MyMonero and OpenMonero use different status strings
|
||||
THROW_WALLET_EXCEPTION_IF(ores.status != "OK" && ores.status != "success" , error::tx_rejected, ptx.tx, get_rpc_status(ores.status), ores.error);
|
||||
|
@ -6379,7 +6452,7 @@ void wallet2::commit_tx(pending_tx& ptx)
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = epee::net_utils::invoke_http_json("/sendrawtransaction", req, daemon_send_resp, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json("/sendrawtransaction", req, daemon_send_resp, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, daemon_send_resp, "sendrawtransaction", error::tx_rejected, ptx.tx, get_rpc_status(daemon_send_resp.status), get_text_reason(daemon_send_resp));
|
||||
check_rpc_cost("/sendrawtransaction", daemon_send_resp.credits, pre_call_credits, COST_PER_TX_RELAY);
|
||||
}
|
||||
|
@ -7349,7 +7422,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
getbh_req.client = get_client_signature();
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, getbh_res, "getblockheadersrange", error::get_blocks_error, get_rpc_status(getbh_res.status));
|
||||
check_rpc_cost("/sendrawtransaction", getbh_res.credits, pre_call_credits, N * COST_PER_BLOCK_HEADER);
|
||||
}
|
||||
|
@ -7575,7 +7648,7 @@ bool wallet2::find_and_save_rings(bool force)
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/gettransactions");
|
||||
THROW_WALLET_EXCEPTION_IF(res.txs.size() != req.txs_hashes.size(), error::wallet_internal_error,
|
||||
"daemon returned wrong response for gettransactions, wrong txs count = " +
|
||||
|
@ -7723,7 +7796,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
|
|||
|
||||
{
|
||||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
|
||||
bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, *m_http_client, rpc_timeout, "POST");
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
|
||||
THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
|
||||
|
@ -7911,7 +7984,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req_t.client = get_client_signature();
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_histogram", error::get_histogram_error, get_rpc_status(resp_t.status));
|
||||
check_rpc_cost("get_output_histogram", resp_t.credits, pre_call_credits, COST_PER_OUTPUT_HISTOGRAM * req_t.amounts.size());
|
||||
}
|
||||
|
@ -7937,7 +8010,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req_t.client = get_client_signature();
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout * 1000);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, *m_http_client, rpc_timeout * 1000);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_distribution", error::get_output_distribution, get_rpc_status(resp_t.status));
|
||||
uint64_t expected_cost = 0;
|
||||
for (uint64_t amount: req_t.amounts) expected_cost += (amount ? COST_PER_OUTPUT_DISTRIBUTION : COST_PER_OUTPUT_DISTRIBUTION_0);
|
||||
|
@ -8291,7 +8364,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, daemon_resp, "get_outs.bin", error::get_outs_error, get_rpc_status(daemon_resp.status));
|
||||
THROW_WALLET_EXCEPTION_IF(daemon_resp.outs.size() != req.outputs.size(), error::wallet_internal_error,
|
||||
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
|
||||
|
@ -10500,7 +10573,7 @@ uint8_t wallet2::get_current_hard_fork()
|
|||
|
||||
m_daemon_rpc_mutex.lock();
|
||||
req_t.version = 0;
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "hard_fork_info", req_t, resp_t, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "hard_fork_info", req_t, resp_t, *m_http_client, rpc_timeout);
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
THROW_WALLET_EXCEPTION_IF(!r, tools::error::no_connection_to_daemon, "hard_fork_info");
|
||||
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, "hard_fork_info");
|
||||
|
@ -10595,7 +10668,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req_t.client = get_client_signature();
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_histogram", error::get_histogram_error, resp_t.status);
|
||||
uint64_t cost = req_t.amounts.empty() ? COST_PER_FULL_OUTPUT_HISTOGRAM : (COST_PER_OUTPUT_HISTOGRAM * req_t.amounts.size());
|
||||
check_rpc_cost("get_output_histogram", resp_t.credits, pre_call_credits, cost);
|
||||
|
@ -10637,7 +10710,7 @@ uint64_t wallet2::get_num_rct_outputs()
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req_t.client = get_client_signature();
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, resp_t, "get_output_histogram", error::get_histogram_error, resp_t.status);
|
||||
THROW_WALLET_EXCEPTION_IF(resp_t.histogram.size() != 1, error::get_histogram_error, "Expected exactly one response");
|
||||
THROW_WALLET_EXCEPTION_IF(resp_t.histogram[0].amount != 0, error::get_histogram_error, "Expected 0 amount");
|
||||
|
@ -10768,7 +10841,7 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
req.client = get_client_signature();
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
|
||||
bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
|
||||
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
|
||||
error::wallet_internal_error, "Failed to get transaction from daemon");
|
||||
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, res.txs.size() * COST_PER_TX);
|
||||
|
@ -10821,7 +10894,7 @@ void wallet2::set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/gettransactions");
|
||||
THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
|
||||
"daemon returned wrong response for gettransactions, wrong txs count = " +
|
||||
|
@ -10874,7 +10947,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "gettransactions");
|
||||
THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
|
||||
"daemon returned wrong response for gettransactions, wrong txs count = " +
|
||||
|
@ -10938,7 +11011,7 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
|
||||
r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_outs.bin", error::get_outs_error, res.status);
|
||||
THROW_WALLET_EXCEPTION_IF(res.outs.size() != ring_size, error::wallet_internal_error,
|
||||
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
|
||||
|
@ -10996,7 +11069,7 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "gettransactions");
|
||||
THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error,
|
||||
"daemon returned wrong response for gettransactions, wrong txs count = " +
|
||||
|
@ -11071,7 +11144,7 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
|
||||
r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_outs.bin", error::get_outs_error, res.status);
|
||||
THROW_WALLET_EXCEPTION_IF(res.outs.size() != req.outputs.size(), error::wallet_internal_error,
|
||||
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
|
||||
|
@ -11173,7 +11246,7 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
|
||||
ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
|
||||
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
|
||||
error::wallet_internal_error, "Failed to get transaction from daemon");
|
||||
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, COST_PER_TX);
|
||||
|
@ -11228,7 +11301,7 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
|
||||
ok = net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
|
||||
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
|
||||
error::wallet_internal_error, "Failed to get transaction from daemon");
|
||||
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, COST_PER_TX);
|
||||
|
@ -11389,7 +11462,7 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
|
||||
ok = net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client);
|
||||
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
|
||||
error::wallet_internal_error, "Failed to get transaction from daemon");
|
||||
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, COST_PER_TX);
|
||||
|
@ -11686,7 +11759,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
gettx_req.client = get_client_signature();
|
||||
bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, m_http_client);
|
||||
bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, *m_http_client);
|
||||
THROW_WALLET_EXCEPTION_IF(!ok || gettx_res.txs.size() != proofs.size(),
|
||||
error::wallet_internal_error, "Failed to get transaction from daemon");
|
||||
check_rpc_cost("/gettransactions", gettx_res.credits, pre_call_credits, gettx_res.txs.size() * COST_PER_TX);
|
||||
|
@ -11703,7 +11776,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
kispent_req.client = get_client_signature();
|
||||
ok = epee::net_utils::invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, m_http_client, rpc_timeout);
|
||||
ok = epee::net_utils::invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, *m_http_client, rpc_timeout);
|
||||
THROW_WALLET_EXCEPTION_IF(!ok || kispent_res.spent_status.size() != proofs.size(),
|
||||
error::wallet_internal_error, "Failed to get key image spent status from daemon");
|
||||
check_rpc_cost("/is_key_image_spent", kispent_res.credits, pre_call_credits, kispent_res.spent_status.size() * COST_PER_KEY_IMAGE);
|
||||
|
@ -12266,7 +12339,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, daemon_resp, "is_key_image_spent");
|
||||
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
|
||||
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
|
||||
|
@ -12355,7 +12428,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
gettxs_req.client = get_client_signature();
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, gettxs_res, "gettransactions");
|
||||
THROW_WALLET_EXCEPTION_IF(gettxs_res.txs.size() != spent_txids.size(), error::wallet_internal_error,
|
||||
"daemon returned wrong response for gettransactions, wrong count = " + std::to_string(gettxs_res.txs.size()) + ", expected " + std::to_string(spent_txids.size()));
|
||||
|
@ -13296,7 +13369,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, m_http_client, rpc_timeout);
|
||||
r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, *m_http_client, rpc_timeout);
|
||||
if (r && res.status == CORE_RPC_STATUS_OK)
|
||||
check_rpc_cost("/getblocks_by_height.bin", res.credits, pre_call_credits, 3 * COST_PER_BLOCK);
|
||||
}
|
||||
|
@ -13374,7 +13447,7 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::
|
|||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, m_http_client, rpc_timeout);
|
||||
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR(r, {}, res, "get_txpool_backlog", error::get_tx_pool_error);
|
||||
check_rpc_cost("get_txpool_backlog", res.credits, pre_call_credits, COST_PER_TX_POOL_STATS * res.backlog.size());
|
||||
}
|
||||
|
@ -13532,10 +13605,12 @@ boost::optional<epee::wipeable_string> wallet2::on_device_pin_request()
|
|||
return boost::none;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
boost::optional<epee::wipeable_string> wallet2::on_device_passphrase_request(bool on_device)
|
||||
boost::optional<epee::wipeable_string> wallet2::on_device_passphrase_request(bool & on_device)
|
||||
{
|
||||
if (nullptr != m_callback)
|
||||
return m_callback->on_device_passphrase_request(on_device);
|
||||
else
|
||||
on_device = true;
|
||||
return boost::none;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
@ -13709,12 +13784,12 @@ void wallet2::finish_rescan_bc_keep_key_images(uint64_t transfer_height, const c
|
|||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_bytes_sent() const
|
||||
{
|
||||
return m_http_client.get_bytes_sent();
|
||||
return m_http_client->get_bytes_sent();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_bytes_received() const
|
||||
{
|
||||
return m_http_client.get_bytes_received();
|
||||
return m_http_client->get_bytes_received();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
|
||||
|
@ -13727,7 +13802,7 @@ std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
|
|||
|
||||
{
|
||||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
bool r = epee::net_utils::invoke_http_json("/get_public_nodes", req, res, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json("/get_public_nodes", req, res, *m_http_client, rpc_timeout);
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, {}, res, "/get_public_nodes");
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ private:
|
|||
virtual void on_device_button_request(uint64_t code) {}
|
||||
virtual void on_device_button_pressed() {}
|
||||
virtual boost::optional<epee::wipeable_string> on_device_pin_request() { return boost::none; }
|
||||
virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device) { return boost::none; }
|
||||
virtual boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device) { on_device = true; return boost::none; }
|
||||
virtual void on_device_progress(const hw::device_progress& event) {};
|
||||
// Common callbacks
|
||||
virtual void on_pool_tx_removed(const crypto::hash &txid) {}
|
||||
|
@ -159,7 +159,7 @@ private:
|
|||
void on_button_request(uint64_t code=0) override;
|
||||
void on_button_pressed() override;
|
||||
boost::optional<epee::wipeable_string> on_pin_request() override;
|
||||
boost::optional<epee::wipeable_string> on_passphrase_request(bool on_device) override;
|
||||
boost::optional<epee::wipeable_string> on_passphrase_request(bool & on_device) override;
|
||||
void on_progress(const hw::device_progress& event) override;
|
||||
private:
|
||||
wallet2 * wallet;
|
||||
|
@ -269,7 +269,7 @@ private:
|
|||
static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds);
|
||||
static bool query_device(hw::device::device_type& device_type, const std::string& keys_file_name, const epee::wipeable_string& password, uint64_t kdf_rounds = 1);
|
||||
|
||||
wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, uint64_t kdf_rounds = 1, bool unattended = false);
|
||||
wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, uint64_t kdf_rounds = 1, bool unattended = false, std::unique_ptr<epee::net_utils::http::http_client_factory> http_client_factory = std::unique_ptr<epee::net_utils::http::http_simple_client_factory>(new epee::net_utils::http::http_simple_client_factory()));
|
||||
~wallet2();
|
||||
|
||||
struct multisig_info
|
||||
|
@ -708,7 +708,7 @@ private:
|
|||
*/
|
||||
void rewrite(const std::string& wallet_name, const epee::wipeable_string& password);
|
||||
void write_watch_only_wallet(const std::string& wallet_name, const epee::wipeable_string& password, std::string &new_keys_filename);
|
||||
void load(const std::string& wallet, const epee::wipeable_string& password);
|
||||
void load(const std::string& wallet, const epee::wipeable_string& password, const std::string& keys_buf = "", const std::string& cache_buf = "");
|
||||
void store();
|
||||
/*!
|
||||
* \brief store_to Stores wallet to another file(s), deleting old ones
|
||||
|
@ -716,6 +716,19 @@ private:
|
|||
* \param password Password to protect new wallet (TODO: probably better save the password in the wallet object?)
|
||||
*/
|
||||
void store_to(const std::string &path, const epee::wipeable_string &password);
|
||||
/*!
|
||||
* \brief get_keys_file_data Get wallet keys data which can be stored to a wallet file.
|
||||
* \param password Password of the encrypted wallet buffer (TODO: probably better save the password in the wallet object?)
|
||||
* \param watch_only true to include only view key, false to include both spend and view keys
|
||||
* \return Encrypted wallet keys data which can be stored to a wallet file
|
||||
*/
|
||||
boost::optional<wallet2::keys_file_data> get_keys_file_data(const epee::wipeable_string& password, bool watch_only);
|
||||
/*!
|
||||
* \brief get_cache_file_data Get wallet cache data which can be stored to a wallet file.
|
||||
* \param password Password to protect the wallet cache data (TODO: probably better save the password in the wallet object?)
|
||||
* \return Encrypted wallet cache data which can be stored to a wallet file
|
||||
*/
|
||||
boost::optional<wallet2::cache_file_data> get_cache_file_data(const epee::wipeable_string& password);
|
||||
|
||||
std::string path() const;
|
||||
|
||||
|
@ -1319,25 +1332,25 @@ private:
|
|||
crypto::public_key get_multisig_signing_public_key(const crypto::secret_key &skey) const;
|
||||
|
||||
template<class t_request, class t_response>
|
||||
inline bool invoke_http_json(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
|
||||
inline bool invoke_http_json(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST")
|
||||
{
|
||||
if (m_offline) return false;
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
|
||||
return epee::net_utils::invoke_http_json(uri, req, res, m_http_client, timeout, http_method);
|
||||
return epee::net_utils::invoke_http_json(uri, req, res, *m_http_client, timeout, http_method);
|
||||
}
|
||||
template<class t_request, class t_response>
|
||||
inline bool invoke_http_bin(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
|
||||
inline bool invoke_http_bin(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST")
|
||||
{
|
||||
if (m_offline) return false;
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
|
||||
return epee::net_utils::invoke_http_bin(uri, req, res, m_http_client, timeout, http_method);
|
||||
return epee::net_utils::invoke_http_bin(uri, req, res, *m_http_client, timeout, http_method);
|
||||
}
|
||||
template<class t_request, class t_response>
|
||||
inline bool invoke_http_json_rpc(const boost::string_ref uri, const std::string& method_name, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
|
||||
inline bool invoke_http_json_rpc(const boost::string_ref uri, const std::string& method_name, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "POST", const std::string& req_id = "0")
|
||||
{
|
||||
if (m_offline) return false;
|
||||
boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
|
||||
return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, m_http_client, timeout, http_method, req_id);
|
||||
return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, *m_http_client, timeout, http_method, req_id);
|
||||
}
|
||||
|
||||
bool set_ring_database(const std::string &filename);
|
||||
|
@ -1403,11 +1416,18 @@ private:
|
|||
*/
|
||||
bool store_keys(const std::string& keys_file_name, const epee::wipeable_string& password, bool watch_only = false);
|
||||
/*!
|
||||
* \brief Load wallet information from wallet file.
|
||||
* \brief Load wallet keys information from wallet file.
|
||||
* \param keys_file_name Name of wallet file
|
||||
* \param password Password of wallet file
|
||||
*/
|
||||
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
|
||||
/*!
|
||||
* \brief Load wallet keys information from a string buffer.
|
||||
* \param keys_buf Keys buffer to load
|
||||
* \param password Password of keys buffer
|
||||
*/
|
||||
bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password);
|
||||
bool load_keys_buf(const std::string& keys_buf, const epee::wipeable_string& password, boost::optional<crypto::chacha_key>& keys_to_encrypt);
|
||||
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
|
||||
bool should_skip_block(const cryptonote::block &b, uint64_t height) const;
|
||||
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
|
||||
|
@ -1487,7 +1507,7 @@ private:
|
|||
void on_device_button_request(uint64_t code);
|
||||
void on_device_button_pressed();
|
||||
boost::optional<epee::wipeable_string> on_device_pin_request();
|
||||
boost::optional<epee::wipeable_string> on_device_passphrase_request(bool on_device);
|
||||
boost::optional<epee::wipeable_string> on_device_passphrase_request(bool & on_device);
|
||||
void on_device_progress(const hw::device_progress& event);
|
||||
|
||||
std::string get_rpc_status(const std::string &s) const;
|
||||
|
@ -1502,7 +1522,7 @@ private:
|
|||
std::string m_wallet_file;
|
||||
std::string m_keys_file;
|
||||
std::string m_mms_file;
|
||||
epee::net_utils::http::http_simple_client m_http_client;
|
||||
const std::unique_ptr<epee::net_utils::http::abstract_http_client> m_http_client;
|
||||
hashchain m_blockchain;
|
||||
std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
|
||||
std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
|
||||
|
|
|
@ -85,7 +85,7 @@ bool wallet2::make_rpc_payment(uint32_t nonce, uint32_t cookie, uint64_t &credit
|
|||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
epee::json_rpc::error error;
|
||||
bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", "rpc_access_submit_nonce", req, res, error, m_http_client, rpc_timeout);
|
||||
bool r = epee::net_utils::invoke_http_json_rpc("/json_rpc", "rpc_access_submit_nonce", req, res, error, *m_http_client, rpc_timeout);
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
THROW_ON_RPC_RESPONSE_ERROR_GENERIC(r, error, res, "rpc_access_submit_nonce");
|
||||
THROW_WALLET_EXCEPTION_IF(res.credits < pre_call_credits, error::wallet_internal_error, "RPC payment did not increase balance");
|
||||
|
|
|
@ -34,8 +34,8 @@ try:
|
|||
except:
|
||||
tests = DEFAULT_TESTS
|
||||
|
||||
N_MONERODS = 2
|
||||
N_WALLETS = 4
|
||||
N_MONERODS = 3
|
||||
N_WALLETS = 7
|
||||
WALLET_DIRECTORY = builddir + "/functional-tests-directory"
|
||||
DIFFICULTY = 10
|
||||
|
||||
|
@ -43,9 +43,17 @@ monerod_base = [builddir + "/bin/monerod", "--regtest", "--fixed-difficulty", st
|
|||
monerod_extra = [
|
||||
[],
|
||||
["--rpc-payment-address", "44SKxxLQw929wRF6BA9paQ1EWFshNnKhXM3qz6Mo3JGDE2YG3xyzVutMStEicxbQGRfrYvAAYxH6Fe8rnD56EaNwUiqhcwR", "--rpc-payment-difficulty", str(DIFFICULTY), "--rpc-payment-credits", "5000", "--data-dir", builddir + "/functional-tests-directory/monerod1"],
|
||||
["--rpc-restricted-bind-port", "18482", "--data-dir", builddir + "/functional-tests-directory/monerod2"]
|
||||
]
|
||||
wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--daemon-port", "18180", "--log-level", "1"]
|
||||
wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--log-level", "1"]
|
||||
wallet_extra = [
|
||||
["--daemon-port", "18180"],
|
||||
["--daemon-port", "18180"],
|
||||
["--daemon-port", "18180"],
|
||||
["--daemon-port", "18180"],
|
||||
["--daemon-port", "18182"],
|
||||
["--daemon-port", "18182"],
|
||||
["--daemon-port", "18182"]
|
||||
]
|
||||
|
||||
command_lines = []
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <stdio.h>
|
||||
#include "misc_language.h"
|
||||
#include "string_tools.h"
|
||||
#include "rpc/rpc_payment_signature.h"
|
||||
|
||||
|
@ -69,6 +70,7 @@ int main(int argc, const char **argv)
|
|||
while (count--)
|
||||
{
|
||||
std::string signature = cryptonote::make_rpc_payment_signature(skey);
|
||||
epee::misc_utils::sleep_no_w(1);
|
||||
printf("%s\n", signature.c_str());
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -59,12 +59,14 @@ class RPCPaymentTest():
|
|||
return fields
|
||||
|
||||
def refill_signatures(self):
|
||||
self.signatures_time = time.time()
|
||||
self.signatures = []
|
||||
signatures = subprocess.check_output([self.make_test_signature, self.secret_key, '256']).decode('utf-8')
|
||||
for line in signatures.split():
|
||||
self.signatures.append(line.rstrip())
|
||||
|
||||
def get_signature(self):
|
||||
if len(self.signatures) == 0:
|
||||
if len(self.signatures) == 0 or self.signatures_time + 10 < time.time():
|
||||
self.refill_signatures()
|
||||
s = self.signatures[0]
|
||||
self.signatures = self.signatures[1:]
|
||||
|
|
|
@ -55,7 +55,7 @@ class TransferTest():
|
|||
|
||||
def reset(self):
|
||||
print('Resetting blockchain')
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
res = daemon.get_height()
|
||||
daemon.pop_blocks(res.height - 1)
|
||||
daemon.flush_txpool()
|
||||
|
@ -69,7 +69,7 @@ class TransferTest():
|
|||
]
|
||||
self.wallet = [None] * len(seeds)
|
||||
for i in range(len(seeds)):
|
||||
self.wallet[i] = Wallet(idx = i)
|
||||
self.wallet[i] = Wallet(idx = i + 4)
|
||||
# close the wallet if any, will throw if none is loaded
|
||||
try: self.wallet[i].close_wallet()
|
||||
except: pass
|
||||
|
@ -77,7 +77,7 @@ class TransferTest():
|
|||
|
||||
def mine(self):
|
||||
print("Mining some blocks")
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
|
||||
res = daemon.get_info()
|
||||
height = res.height
|
||||
|
@ -89,7 +89,7 @@ class TransferTest():
|
|||
assert res.height == height + 80
|
||||
|
||||
def transfer(self):
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
|
||||
print("Creating transfer to self")
|
||||
|
||||
|
@ -508,7 +508,7 @@ class TransferTest():
|
|||
def check_get_bulk_payments(self):
|
||||
print('Checking get_bulk_payments')
|
||||
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
res = daemon.get_info()
|
||||
height = res.height
|
||||
|
||||
|
@ -544,7 +544,7 @@ class TransferTest():
|
|||
def check_get_payments(self):
|
||||
print('Checking get_payments')
|
||||
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
res = daemon.get_info()
|
||||
height = res.height
|
||||
|
||||
|
@ -587,7 +587,8 @@ class TransferTest():
|
|||
assert len(res.tx_blob_list) == 1
|
||||
txes[i][1] = res.tx_blob_list[0]
|
||||
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
restricted_daemon = Daemon(idx = 2, restricted_rpc = True)
|
||||
res = daemon.send_raw_transaction(txes[0][1])
|
||||
assert res.not_relayed == False
|
||||
assert res.low_mixin == False
|
||||
|
@ -598,6 +599,18 @@ class TransferTest():
|
|||
assert res.overspend == False
|
||||
assert res.fee_too_low == False
|
||||
|
||||
res = restricted_daemon.send_raw_transaction(txes[0][1])
|
||||
assert res.not_relayed == False
|
||||
assert res.low_mixin == False
|
||||
assert res.double_spend == False
|
||||
assert res.invalid_input == False
|
||||
assert res.invalid_output == False
|
||||
assert res.too_big == False
|
||||
assert res.overspend == False
|
||||
assert res.fee_too_low == False
|
||||
|
||||
res = restricted_daemon.get_transactions([txes[0][0]])
|
||||
assert not 'txs' in res or len(res.txs) == 0
|
||||
res = daemon.get_transactions([txes[0][0]])
|
||||
assert len(res.txs) >= 1
|
||||
tx = [tx for tx in res.txs if tx.tx_hash == txes[0][0]][0]
|
||||
|
@ -615,6 +628,19 @@ class TransferTest():
|
|||
assert res.fee_too_low == False
|
||||
assert res.too_few_outputs == False
|
||||
|
||||
res = restricted_daemon.send_raw_transaction(txes[1][1])
|
||||
assert res.not_relayed == False
|
||||
assert res.low_mixin == False
|
||||
assert res.double_spend == True
|
||||
assert res.invalid_input == False
|
||||
assert res.invalid_output == False
|
||||
assert res.too_big == False
|
||||
assert res.overspend == False
|
||||
assert res.fee_too_low == False
|
||||
assert res.too_few_outputs == False
|
||||
|
||||
res = restricted_daemon.get_transactions([txes[0][0]])
|
||||
assert not 'txs' in res or len(res.txs) == 0
|
||||
res = daemon.get_transactions([txes[0][0]])
|
||||
assert len(res.txs) >= 1
|
||||
tx = [tx for tx in res.txs if tx.tx_hash == txes[0][0]][0]
|
||||
|
@ -623,13 +649,13 @@ class TransferTest():
|
|||
|
||||
def sweep_dust(self):
|
||||
print("Sweeping dust")
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
self.wallet[0].refresh()
|
||||
res = self.wallet[0].sweep_dust()
|
||||
assert not 'tx_hash_list' in res or len(res.tx_hash_list) == 0 # there's just one, but it cannot meet the fee
|
||||
|
||||
def sweep_single(self):
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
|
||||
print("Sending single output")
|
||||
|
||||
|
@ -685,7 +711,7 @@ class TransferTest():
|
|||
assert len([t for t in res.transfers if t.key_image == ki]) == 1
|
||||
|
||||
def check_destinations(self):
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
|
||||
print("Checking transaction destinations")
|
||||
|
||||
|
@ -741,7 +767,7 @@ class TransferTest():
|
|||
self.wallet[0].refresh()
|
||||
|
||||
def check_tx_notes(self):
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
|
||||
print('Testing tx notes')
|
||||
res = self.wallet[0].get_transfers()
|
||||
|
@ -758,7 +784,7 @@ class TransferTest():
|
|||
assert res.notes == ['out txid', 'in txid']
|
||||
|
||||
def check_rescan(self):
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
|
||||
print('Testing rescan_spent')
|
||||
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
||||
|
@ -798,7 +824,7 @@ class TransferTest():
|
|||
assert sorted(old_t_out, key = lambda k: k['txid']) == sorted(new_t_out, key = lambda k: k['txid'])
|
||||
|
||||
def check_is_key_image_spent(self):
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx = 2)
|
||||
|
||||
print('Testing is_key_image_spent')
|
||||
res = self.wallet[0].incoming_transfers(transfer_type = 'all')
|
||||
|
|
|
@ -45,14 +45,14 @@ class TransferTest():
|
|||
|
||||
def reset(self):
|
||||
print('Resetting blockchain')
|
||||
daemon = Daemon()
|
||||
daemon = Daemon(idx=2)
|
||||
res = daemon.get_height()
|
||||
daemon.pop_blocks(res.height - 1)
|
||||
daemon.flush_txpool()
|
||||
|
||||
def create(self):
|
||||
print('Creating wallet')
|
||||
wallet = Wallet()
|
||||
wallet = Wallet(idx = 4)
|
||||
# close the wallet if any, will throw if none is loaded
|
||||
try: wallet.close_wallet()
|
||||
except: pass
|
||||
|
@ -61,8 +61,8 @@ class TransferTest():
|
|||
|
||||
def mine(self):
|
||||
print("Mining some blocks")
|
||||
daemon = Daemon()
|
||||
wallet = Wallet()
|
||||
daemon = Daemon(idx = 2)
|
||||
wallet = Wallet(idx = 4)
|
||||
|
||||
daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 80)
|
||||
wallet.refresh()
|
||||
|
@ -70,8 +70,8 @@ class TransferTest():
|
|||
def create_txes(self, address, ntxes):
|
||||
print('Creating ' + str(ntxes) + ' transactions')
|
||||
|
||||
daemon = Daemon()
|
||||
wallet = Wallet()
|
||||
daemon = Daemon(idx = 2)
|
||||
wallet = Wallet(idx = 4)
|
||||
|
||||
dst = {'address': address, 'amount': 1000000000000}
|
||||
|
||||
|
@ -83,8 +83,10 @@ class TransferTest():
|
|||
return txes
|
||||
|
||||
def check_empty_pool(self):
|
||||
daemon = Daemon()
|
||||
self.check_empty_rpc_pool(Daemon(idx = 2))
|
||||
self.check_empty_rpc_pool(Daemon(idx = 2, restricted_rpc = True))
|
||||
|
||||
def check_empty_rpc_pool(self, daemon):
|
||||
res = daemon.get_transaction_pool_hashes()
|
||||
assert not 'tx_hashes' in res or len(res.tx_hashes) == 0
|
||||
res = daemon.get_transaction_pool_stats()
|
||||
|
@ -103,8 +105,9 @@ class TransferTest():
|
|||
assert res.pool_stats.num_double_spends == 0
|
||||
|
||||
def check_txpool(self):
|
||||
daemon = Daemon()
|
||||
wallet = Wallet()
|
||||
daemon = Daemon(idx = 2)
|
||||
restricted_daemon = Daemon(idx = 2, restricted_rpc = True)
|
||||
wallet = Wallet(idx = 4)
|
||||
|
||||
res = daemon.get_info()
|
||||
height = res.height
|
||||
|
@ -117,6 +120,7 @@ class TransferTest():
|
|||
res = daemon.get_info()
|
||||
assert res.tx_pool_size == txpool_size + 5
|
||||
txpool_size = res.tx_pool_size
|
||||
self.check_empty_rpc_pool(restricted_daemon)
|
||||
|
||||
res = daemon.get_transaction_pool()
|
||||
assert len(res.transactions) == txpool_size
|
||||
|
@ -160,6 +164,7 @@ class TransferTest():
|
|||
print('Flushing 2 transactions')
|
||||
txes_keys = list(txes.keys())
|
||||
daemon.flush_txpool([txes_keys[1], txes_keys[3]])
|
||||
self.check_empty_rpc_pool(restricted_daemon)
|
||||
res = daemon.get_transaction_pool()
|
||||
assert len(res.transactions) == txpool_size - 2
|
||||
assert len([x for x in res.transactions if x.id_hash == txes_keys[1]]) == 0
|
||||
|
@ -210,6 +215,7 @@ class TransferTest():
|
|||
print('Flushing unknown transactions')
|
||||
unknown_txids = ['1'*64, '2'*64, '3'*64]
|
||||
daemon.flush_txpool(unknown_txids)
|
||||
self.check_empty_rpc_pool(restricted_daemon)
|
||||
res = daemon.get_transaction_pool()
|
||||
assert len(res.transactions) == txpool_size - 2
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "include_base_utils.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "net/http_client.h"
|
||||
#include "net/net_ssl.h"
|
||||
#include "fuzzer.h"
|
||||
|
||||
class dummy_client
|
||||
|
@ -46,6 +47,10 @@ public:
|
|||
data.clear();
|
||||
return true;
|
||||
}
|
||||
void set_ssl(epee::net_utils::ssl_options_t ssl_options) { }
|
||||
bool is_connected(bool *ssl = NULL) { return true; }
|
||||
uint64_t get_bytes_sent() const { return 1; }
|
||||
uint64_t get_bytes_received() const { return 1; }
|
||||
|
||||
void set_test_data(const std::string &s) { data = s; }
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ enum test_op
|
|||
op_scalarmultKey,
|
||||
op_scalarmultH,
|
||||
op_scalarmult8,
|
||||
op_scalarmult8_p3,
|
||||
op_ge_dsm_precomp,
|
||||
op_ge_double_scalarmult_base_vartime,
|
||||
op_ge_double_scalarmult_precomp_vartime,
|
||||
|
@ -105,6 +106,7 @@ public:
|
|||
case op_scalarmultKey: rct::scalarmultKey(point0, scalar0); break;
|
||||
case op_scalarmultH: rct::scalarmultH(scalar0); break;
|
||||
case op_scalarmult8: rct::scalarmult8(point0); break;
|
||||
case op_scalarmult8_p3: rct::scalarmult8(p3_0,point0); break;
|
||||
case op_ge_dsm_precomp: ge_dsm_precomp(dsmp, &p3_0); break;
|
||||
case op_ge_double_scalarmult_base_vartime: ge_double_scalarmult_base_vartime(&tmp_p2, scalar0.bytes, &p3_0, scalar1.bytes); break;
|
||||
case op_ge_double_scalarmult_precomp_vartime: ge_double_scalarmult_precomp_vartime(&tmp_p2, scalar0.bytes, &p3_0, scalar1.bytes, precomp0); break;
|
||||
|
|
|
@ -254,6 +254,7 @@ int main(int argc, char** argv)
|
|||
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_scalarmultKey);
|
||||
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_scalarmultH);
|
||||
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_scalarmult8);
|
||||
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_scalarmult8_p3);
|
||||
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_dsm_precomp);
|
||||
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_base_vartime);
|
||||
TEST_PERFORMANCE1(filter, p, test_crypto_ops, op_ge_double_scalarmult_precomp_vartime);
|
||||
|
|
|
@ -129,7 +129,7 @@ void mock_daemon::init()
|
|||
m_rpc_server.nettype(m_network_type);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(m_protocol.init(m_vm), "Failed to initialize cryptonote protocol.");
|
||||
CHECK_AND_ASSERT_THROW_MES(m_rpc_server.init(m_vm, false, main_rpc_port), "Failed to initialize RPC server.");
|
||||
CHECK_AND_ASSERT_THROW_MES(m_rpc_server.init(m_vm, false, main_rpc_port, false), "Failed to initialize RPC server.");
|
||||
|
||||
if (m_start_p2p)
|
||||
CHECK_AND_ASSERT_THROW_MES(m_server.init(m_vm), "Failed to initialize p2p server.");
|
||||
|
@ -313,7 +313,7 @@ void mock_daemon::mine_blocks(size_t num_blocks, const std::string &miner_addres
|
|||
{
|
||||
bool blocks_mined = false;
|
||||
const uint64_t start_height = get_height();
|
||||
const auto mining_timeout = std::chrono::seconds(30);
|
||||
const auto mining_timeout = std::chrono::seconds(120);
|
||||
MDEBUG("Current height before mining: " << start_height);
|
||||
|
||||
start_mining(miner_address);
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
typedef cryptonote::t_cryptonote_protocol_handler<cryptonote::core> t_protocol_raw;
|
||||
typedef nodetool::node_server<t_protocol_raw> t_node_server;
|
||||
|
||||
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::seconds(60);
|
||||
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::seconds(120);
|
||||
|
||||
cryptonote::core * m_core;
|
||||
t_protocol_raw m_protocol;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
using namespace cryptonote;
|
||||
|
||||
#include <boost/regex.hpp>
|
||||
#include <common/apply_permutation.h>
|
||||
#include "common/util.h"
|
||||
#include "common/command_line.h"
|
||||
#include "trezor_tests.h"
|
||||
|
@ -74,7 +75,8 @@ namespace
|
|||
try { \
|
||||
setup_chain(core, trezor_base, chain_path, fix_chain, vm_core); \
|
||||
} catch (const std::exception& ex) { \
|
||||
failed_tests.emplace_back("gen_trezor_base " #NAME); \
|
||||
MERROR("Chain setup failed for " << NAME); \
|
||||
throw; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
@ -136,10 +138,11 @@ int main(int argc, char* argv[])
|
|||
hw::register_device(HW_TREZOR_NAME, ensure_trezor_test_device()); // shim device for call tracking
|
||||
|
||||
// Bootstrapping common chain & accounts
|
||||
const uint8_t initial_hf = (uint8_t)get_env_long("TEST_MIN_HF", 11);
|
||||
const uint8_t max_hf = (uint8_t)get_env_long("TEST_MAX_HF", 11);
|
||||
const uint8_t initial_hf = (uint8_t)get_env_long("TEST_MIN_HF", 12);
|
||||
const uint8_t max_hf = (uint8_t)get_env_long("TEST_MAX_HF", 12);
|
||||
auto sync_test = get_env_long("TEST_KI_SYNC", 1);
|
||||
MINFO("Test versions " << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")");
|
||||
MINFO("Testing hardforks [" << (int)initial_hf << ", " << (int)max_hf << "]");
|
||||
MINFO("Testing hardforks [" << (int)initial_hf << ", " << (int)max_hf << "], sync-test: " << sync_test);
|
||||
|
||||
cryptonote::core core_obj(nullptr);
|
||||
cryptonote::core * const core = &core_obj;
|
||||
|
@ -181,7 +184,7 @@ int main(int argc, char* argv[])
|
|||
trezor_base.daemon(daemon);
|
||||
|
||||
// Hard-fork independent tests
|
||||
if (hf == initial_hf)
|
||||
if (hf == initial_hf && sync_test > 0)
|
||||
{
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_ki_sync_without_refresh, core, trezor_base);
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_live_refresh, core, trezor_base);
|
||||
|
@ -191,7 +194,6 @@ int main(int argc, char* argv[])
|
|||
TREZOR_COMMON_TEST_CASE(gen_trezor_1utxo, core, trezor_base);
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_1utxo_paymentid_short, core, trezor_base);
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_1utxo_paymentid_short_integrated, core, trezor_base);
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_1utxo_paymentid_long, core, trezor_base);
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo, core, trezor_base);
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo_acc1, core, trezor_base);
|
||||
TREZOR_COMMON_TEST_CASE(gen_trezor_4utxo_to_sub, core, trezor_base);
|
||||
|
@ -338,10 +340,7 @@ static void setup_chain(cryptonote::core * core, gen_trezor_base & trezor_base,
|
|||
if (!unserialize_chain_from_file(events, trezor_base, chain_path))
|
||||
{
|
||||
MERROR("Failed to deserialize data from file: " << chain_path);
|
||||
if (!fix_chain)
|
||||
{
|
||||
throw std::runtime_error("Chain load error");
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(fix_chain, "Chain load error");
|
||||
} else
|
||||
{
|
||||
trezor_base.load(events);
|
||||
|
@ -648,6 +647,8 @@ void gen_trezor_base::fork(gen_trezor_base & other)
|
|||
other.m_alice_account = m_alice_account;
|
||||
other.m_eve_account = m_eve_account;
|
||||
other.m_trezor = m_trezor;
|
||||
other.m_generator.set_events(&other.m_events);
|
||||
other.m_generator.set_network_type(m_network_type);
|
||||
}
|
||||
|
||||
void gen_trezor_base::clear()
|
||||
|
@ -700,6 +701,8 @@ bool gen_trezor_base::generate(std::vector<test_event_entry>& events)
|
|||
|
||||
// Events, custom genesis so it matches wallet genesis
|
||||
auto & generator = m_generator; // macro shortcut
|
||||
generator.set_events(&events);
|
||||
generator.set_network_type(m_network_type);
|
||||
|
||||
cryptonote::block blk_gen;
|
||||
std::vector<size_t> block_weights;
|
||||
|
@ -852,6 +855,8 @@ void gen_trezor_base::load(std::vector<test_event_entry>& events)
|
|||
{
|
||||
init_fields();
|
||||
m_events = events;
|
||||
m_generator.set_events(&m_events);
|
||||
m_generator.set_network_type(m_network_type);
|
||||
|
||||
unsigned acc_idx = 0;
|
||||
cryptonote::account_base * accounts[] = {TREZOR_ACCOUNT_ORDERING};
|
||||
|
@ -919,29 +924,19 @@ void gen_trezor_base::rewind_blocks(std::vector<test_event_entry>& events, size_
|
|||
void gen_trezor_base::fix_hf(std::vector<test_event_entry>& events)
|
||||
{
|
||||
// If current test requires higher hard-fork, move it up
|
||||
const auto current_hf = m_hard_forks.back().first;
|
||||
auto current_hf = m_hard_forks.back().first;
|
||||
CHECK_AND_ASSERT_THROW_MES(current_hf <= m_top_hard_fork, "Generated chain hardfork is higher than desired maximum");
|
||||
CHECK_AND_ASSERT_THROW_MES(m_rct_config.bp_version != 2 || m_top_hard_fork >= 10, "Desired maximum is too low for BPv2");
|
||||
|
||||
if (current_hf > m_top_hard_fork)
|
||||
{
|
||||
throw std::runtime_error("Generated chain hardfork is higher than desired maximum");
|
||||
}
|
||||
|
||||
if (m_rct_config.bp_version == 2 && m_top_hard_fork < 10)
|
||||
{
|
||||
throw std::runtime_error("Desired maximum is too low for BPv2");
|
||||
}
|
||||
|
||||
if (current_hf < m_top_hard_fork)
|
||||
for(;current_hf < m_top_hard_fork; current_hf+=1)
|
||||
{
|
||||
auto const hf_to_add = current_hf + 1;
|
||||
auto hardfork_height = num_blocks(events);
|
||||
ADD_HARDFORK(m_hard_forks, m_top_hard_fork, hardfork_height);
|
||||
add_top_hfork(events, m_hard_forks);
|
||||
MDEBUG("Hardfork added at height: " << hardfork_height << ", from " << (int)current_hf << " to " << (int)m_top_hard_fork);
|
||||
|
||||
if (current_hf < 10)
|
||||
{ // buffer blocks, add 10 to apply v10 rules
|
||||
rewind_blocks(events, 10, m_top_hard_fork);
|
||||
}
|
||||
ADD_HARDFORK(m_hard_forks, hf_to_add, hardfork_height);
|
||||
add_top_hfork(events, m_hard_forks);
|
||||
MDEBUG("Hardfork added at height: " << hardfork_height << ", from " << (int)current_hf << " to " << (int)hf_to_add);
|
||||
rewind_blocks(events, 10, hf_to_add);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1271,7 +1266,6 @@ void gen_trezor_base::set_hard_fork(uint8_t hf)
|
|||
|
||||
#define TREZOR_SKIP_IF_VERSION_LEQ(x) if (m_trezor->get_version() <= x) { MDEBUG("Test skipped"); return true; }
|
||||
#define TREZOR_TEST_PAYMENT_ID "\xde\xad\xc0\xde\xde\xad\xc0\xde"
|
||||
#define TREZOR_TEST_PAYMENT_ID_LONG "\xde\xad\xc0\xde\xde\xad\xc0\xde\xde\xad\xc0\xde\xde\xad\xc0\xde\xde\xad\xc0\xde\xde\xad\xc0\xde\xde\xad\xc0\xde\xde\xad\xc0\xde"
|
||||
|
||||
tsx_builder * tsx_builder::sources(std::vector<cryptonote::tx_source_entry> & sources, std::vector<size_t> & selected_transfers)
|
||||
{
|
||||
|
@ -1424,13 +1418,26 @@ tsx_builder * tsx_builder::construct_pending_tx(tools::wallet2::pending_tx &ptx,
|
|||
std::vector<crypto::secret_key> additional_tx_keys;
|
||||
std::vector<tx_destination_entry> destinations_copy = m_destinations;
|
||||
|
||||
auto sources_copy = m_sources;
|
||||
auto change_addr = m_from->get_account().get_keys().m_account_address;
|
||||
bool r = construct_tx_and_get_tx_key(m_from->get_account().get_keys(), subaddresses, m_sources, destinations_copy,
|
||||
change_addr, extra ? extra.get() : std::vector<uint8_t>(), tx, 0, tx_key,
|
||||
additional_tx_keys, true, m_rct_config, nullptr);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Transaction construction failed");
|
||||
|
||||
// Selected transfers permutation
|
||||
std::vector<size_t> ins_order;
|
||||
for (size_t n = 0; n < m_sources.size(); ++n)
|
||||
{
|
||||
for (size_t idx = 0; idx < sources_copy.size(); ++idx)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES((size_t)sources_copy[idx].real_output < sources_copy[idx].outputs.size(), "Invalid real_output");
|
||||
if (sources_copy[idx].outputs[sources_copy[idx].real_output].second.dest == m_sources[n].outputs[m_sources[n].real_output].second.dest)
|
||||
ins_order.push_back(idx);
|
||||
}
|
||||
}
|
||||
CHECK_AND_ASSERT_THROW_MES(ins_order.size() == m_sources.size(), "Failed to work out sources permutation");
|
||||
|
||||
ptx.key_images = "";
|
||||
ptx.fee = TESTS_DEFAULT_FEE;
|
||||
ptx.dust = 0;
|
||||
|
@ -1438,6 +1445,7 @@ tsx_builder * tsx_builder::construct_pending_tx(tools::wallet2::pending_tx &ptx,
|
|||
ptx.tx = tx;
|
||||
ptx.change_dts = m_destinations.back();
|
||||
ptx.selected_transfers = m_selected_transfers;
|
||||
tools::apply_permutation(ins_order, ptx.selected_transfers);
|
||||
ptx.tx_key = tx_key;
|
||||
ptx.additional_tx_keys = additional_tx_keys;
|
||||
ptx.dests = m_destinations;
|
||||
|
@ -1671,22 +1679,6 @@ bool gen_trezor_1utxo_paymentid_short_integrated::generate(std::vector<test_even
|
|||
TREZOR_TEST_SUFFIX();
|
||||
}
|
||||
|
||||
bool gen_trezor_1utxo_paymentid_long::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
TREZOR_TEST_PREFIX();
|
||||
t_builder->cur_height(num_blocks(events) - 1)
|
||||
->mixin(TREZOR_TEST_MIXIN)
|
||||
->fee(TREZOR_TEST_FEE)
|
||||
->from(m_wl_alice.get(), 0)
|
||||
->compute_sources(boost::none, MK_COINS(1), -1, -1)
|
||||
->add_destination(m_eve_account, false, 1000)
|
||||
->payment_id(TREZOR_TEST_PAYMENT_ID_LONG)
|
||||
->rct_config(m_rct_config)
|
||||
->build_tx();
|
||||
|
||||
TREZOR_TEST_SUFFIX();
|
||||
}
|
||||
|
||||
bool gen_trezor_4utxo::generate(std::vector<test_event_entry>& events)
|
||||
{
|
||||
TREZOR_TEST_PREFIX();
|
||||
|
|
|
@ -264,12 +264,6 @@ public:
|
|||
bool generate(std::vector<test_event_entry>& events) override;
|
||||
};
|
||||
|
||||
class gen_trezor_1utxo_paymentid_long : public gen_trezor_base
|
||||
{
|
||||
public:
|
||||
bool generate(std::vector<test_event_entry>& events) override;
|
||||
};
|
||||
|
||||
class gen_trezor_4utxo : public gen_trezor_base
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -841,6 +841,9 @@ TEST(HexLocale, String)
|
|||
// decoding it this way also, ignoring spaces and colons between the numbers
|
||||
hex.assign("00:ff 0f:f0");
|
||||
EXPECT_EQ(source, epee::from_hex_locale::to_vector(hex));
|
||||
|
||||
hex.append("f0");
|
||||
EXPECT_EQ(source, epee::from_hex_locale::to_vector(boost::string_ref{hex.data(), hex.size() - 2}));
|
||||
}
|
||||
|
||||
TEST(ToHex, Array)
|
||||
|
|
|
@ -583,7 +583,9 @@ TEST_F(levin_notify, stem_without_padding)
|
|||
{
|
||||
const std::size_t sent = context->process_send_queue();
|
||||
if (sent && is_stem)
|
||||
{
|
||||
EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
|
||||
}
|
||||
send_count += sent;
|
||||
}
|
||||
|
||||
|
@ -653,7 +655,9 @@ TEST_F(levin_notify, local_without_padding)
|
|||
{
|
||||
const std::size_t sent = context->process_send_queue();
|
||||
if (sent && is_stem)
|
||||
{
|
||||
EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
|
||||
}
|
||||
send_count += sent;
|
||||
}
|
||||
|
||||
|
|
|
@ -1702,6 +1702,45 @@ TEST(zmq, read_write)
|
|||
EXPECT_EQ(message, *received);
|
||||
}
|
||||
|
||||
TEST(zmq, read_write_slice)
|
||||
{
|
||||
net::zmq::context context{zmq_init(1)};
|
||||
ASSERT_NE(nullptr, context);
|
||||
|
||||
net::zmq::socket send_socket{zmq_socket(context.get(), ZMQ_REQ)};
|
||||
net::zmq::socket recv_socket{zmq_socket(context.get(), ZMQ_REP)};
|
||||
ASSERT_NE(nullptr, send_socket);
|
||||
ASSERT_NE(nullptr, recv_socket);
|
||||
|
||||
ASSERT_EQ(0u, zmq_bind(recv_socket.get(), "inproc://testing"));
|
||||
ASSERT_EQ(0u, zmq_connect(send_socket.get(), "inproc://testing"));
|
||||
|
||||
std::string message;
|
||||
message.resize(1024);
|
||||
crypto::rand(message.size(), reinterpret_cast<std::uint8_t*>(std::addressof(message[0])));
|
||||
|
||||
{
|
||||
epee::byte_slice slice_message{{epee::strspan<std::uint8_t>(message)}};
|
||||
ASSERT_TRUE(bool(net::zmq::send(std::move(slice_message), send_socket.get())));
|
||||
EXPECT_TRUE(slice_message.empty());
|
||||
}
|
||||
|
||||
const expect<std::string> received = net::zmq::receive(recv_socket.get());
|
||||
ASSERT_TRUE(bool(received));
|
||||
EXPECT_EQ(message, *received);
|
||||
}
|
||||
|
||||
TEST(zmq, write_slice_fail)
|
||||
{
|
||||
std::string message;
|
||||
message.resize(1024);
|
||||
crypto::rand(message.size(), reinterpret_cast<std::uint8_t*>(std::addressof(message[0])));
|
||||
|
||||
epee::byte_slice slice_message{std::move(message)};
|
||||
EXPECT_FALSE(bool(net::zmq::send(std::move(slice_message), nullptr)));
|
||||
EXPECT_TRUE(slice_message.empty());
|
||||
}
|
||||
|
||||
TEST(zmq, read_write_multipart)
|
||||
{
|
||||
net::zmq::context context{zmq_init(1)};
|
||||
|
|
|
@ -1077,8 +1077,16 @@ TEST(ringct, H)
|
|||
|
||||
TEST(ringct, mul8)
|
||||
{
|
||||
ge_p3 p3;
|
||||
rct::key key;
|
||||
ASSERT_EQ(rct::scalarmult8(rct::identity()), rct::identity());
|
||||
rct::scalarmult8(p3,rct::identity());
|
||||
ge_p3_tobytes(key.bytes, &p3);
|
||||
ASSERT_EQ(key, rct::identity());
|
||||
ASSERT_EQ(rct::scalarmult8(rct::H), rct::scalarmultKey(rct::H, rct::EIGHT));
|
||||
rct::scalarmult8(p3,rct::H);
|
||||
ge_p3_tobytes(key.bytes, &p3);
|
||||
ASSERT_EQ(key, rct::scalarmultKey(rct::H, rct::EIGHT));
|
||||
ASSERT_EQ(rct::scalarmultKey(rct::scalarmultKey(rct::H, rct::INV_EIGHT), rct::EIGHT), rct::H);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,11 @@ from .rpc import JSONRPC
|
|||
|
||||
class Daemon(object):
|
||||
|
||||
def __init__(self, protocol='http', host='127.0.0.1', port=0, idx=0):
|
||||
def __init__(self, protocol='http', host='127.0.0.1', port=0, idx=0, restricted_rpc = False):
|
||||
base = 18480 if restricted_rpc else 18180
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else 18180+idx))
|
||||
self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else base+idx))
|
||||
|
||||
def getblocktemplate(self, address, prev_block = "", client = ""):
|
||||
getblocktemplate = {
|
||||
|
|
Loading…
Reference in New Issue