aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/depends/packages/boost.mk2
-rw-r--r--contrib/epee/include/math_helper.h39
-rw-r--r--contrib/epee/include/misc_log_ex.h23
-rw-r--r--contrib/epee/include/net/buffer.h62
-rw-r--r--contrib/epee/include/net/http_server_handlers_map2.h2
-rw-r--r--contrib/epee/include/net/levin_base.h4
-rw-r--r--contrib/epee/include/net/levin_client.h4
-rw-r--r--contrib/epee/include/net/levin_client.inl4
-rw-r--r--contrib/epee/include/net/levin_protocol_handler_async.h61
-rw-r--r--contrib/epee/include/span.h8
-rw-r--r--contrib/epee/include/storages/http_abstract_invoke.h2
-rw-r--r--contrib/epee/include/storages/levin_abstract_invoke2.h21
-rw-r--r--contrib/epee/include/storages/parserse_base_utils.h8
-rw-r--r--contrib/epee/include/storages/portable_storage.h6
-rw-r--r--contrib/epee/include/storages/portable_storage_base.h15
-rw-r--r--contrib/epee/include/storages/portable_storage_from_bin.h1
-rw-r--r--contrib/epee/include/storages/portable_storage_template_helper.h8
-rw-r--r--contrib/epee/include/string_tools.h78
-rw-r--r--contrib/epee/src/CMakeLists.txt2
-rw-r--r--contrib/epee/src/buffer.cpp97
-rw-r--r--contrib/epee/src/mlocker.cpp3
-rw-r--r--contrib/epee/src/net_utils_base.cpp6
-rw-r--r--external/easylogging++/easylogging++.cc19
-rw-r--r--external/easylogging++/easylogging++.h2
-rw-r--r--src/blockchain_db/berkeleydb/db_bdb.cpp4
-rw-r--r--src/blockchain_db/blockchain_db.h7
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp52
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h6
-rw-r--r--src/blockchain_utilities/blockchain_blackball.cpp2
-rw-r--r--src/blocks/CMakeLists.txt2
-rw-r--r--src/checkpoints/checkpoints.cpp4
-rw-r--r--src/common/perf_timer.cpp46
-rw-r--r--src/common/perf_timer.h4
-rw-r--r--src/cryptonote_basic/hardfork.cpp24
-rw-r--r--src/cryptonote_basic/hardfork.h10
-rw-r--r--src/cryptonote_core/blockchain.cpp103
-rw-r--r--src/cryptonote_core/blockchain.h4
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp5
-rw-r--r--src/cryptonote_core/cryptonote_core.h1
-rw-r--r--src/cryptonote_protocol/block_queue.cpp1
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h6
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl38
-rw-r--r--src/daemon/command_parser_executor.cpp18
-rw-r--r--src/daemon/rpc_command_executor.cpp12
-rw-r--r--src/daemon/rpc_command_executor.h4
-rw-r--r--src/device_trezor/trezor/protocol.cpp3
-rw-r--r--src/p2p/net_node.h14
-rw-r--r--src/p2p/net_node.inl27
-rw-r--r--src/p2p/net_node_common.h16
-rw-r--r--src/p2p/net_peerlist.h15
-rw-r--r--src/p2p/p2p_protocol_defs.h20
-rw-r--r--src/ringct/rctSigs.cpp11
-rw-r--r--src/rpc/core_rpc_server.cpp60
-rw-r--r--src/simplewallet/simplewallet.cpp197
-rw-r--r--src/simplewallet/simplewallet.h4
-rw-r--r--src/wallet/api/wallet.cpp26
-rw-r--r--src/wallet/api/wallet.h1
-rw-r--r--src/wallet/api/wallet2_api.h6
-rw-r--r--src/wallet/api/wallet_manager.cpp2
-rw-r--r--src/wallet/message_store.cpp14
-rw-r--r--src/wallet/wallet2.cpp250
-rw-r--r--src/wallet/wallet2.h22
-rw-r--r--src/wallet/wallet_rpc_server.cpp2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h5
-rw-r--r--tests/core_tests/chaingen_main.cpp8
-rw-r--r--tests/core_tests/multisig.cpp8
-rw-r--r--tests/core_tests/multisig.h16
-rw-r--r--tests/functional_tests/transactions_flow_test.cpp1
-rw-r--r--tests/fuzz/levin.cpp8
-rw-r--r--tests/net_load_tests/net_load_tests.h5
-rw-r--r--tests/unit_tests/epee_levin_protocol_handler_async.cpp8
-rw-r--r--tests/unit_tests/epee_utils.cpp69
-rw-r--r--tests/unit_tests/test_peerlist.cpp6
-rw-r--r--tests/unit_tests/testdb.h6
-rw-r--r--utils/gpg_keys/erciccione.asc30
-rw-r--r--utils/gpg_keys/moneromooo.asc50
76 files changed, 1179 insertions, 561 deletions
diff --git a/contrib/depends/packages/boost.mk b/contrib/depends/packages/boost.mk
index 89db5a415..e60a1c677 100644
--- a/contrib/depends/packages/boost.mk
+++ b/contrib/depends/packages/boost.mk
@@ -20,7 +20,7 @@ $(package)_archiver_$(host_os)=$($(package)_ar)
$(package)_toolset_darwin=darwin
$(package)_archiver_darwin=$($(package)_libtool)
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
-$(package)_cxxflags=-std=c++11 -fvisibility=hidden
+$(package)_cxxflags=-std=c++11
$(package)_cxxflags_linux=-fPIC
endef
diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h
index ef839f609..e22e8ee6e 100644
--- a/contrib/epee/include/math_helper.h
+++ b/contrib/epee/include/math_helper.h
@@ -230,35 +230,56 @@ namespace math_helper
}
}
- template<int default_interval, bool start_immediate = true>
- class once_a_time_seconds
+ template<uint64_t scale, int default_interval, bool start_immediate = true>
+ class once_a_time
{
+ uint64_t get_time() const
+ {
+#ifdef _WIN32
+ FILETIME fileTime;
+ GetSystemTimeAsFileTime(&fileTime);
+ unsigned __int64 present = 0;
+ present |= fileTime.dwHighDateTime;
+ present = present << 32;
+ present |= fileTime.dwLowDateTime;
+ present /= 10; // mic-sec
+#else
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000 + tv.tv_usec;
+#endif
+ }
+
public:
- once_a_time_seconds():m_interval(default_interval)
+ once_a_time():m_interval(default_interval * scale)
{
m_last_worked_time = 0;
if(!start_immediate)
- time(&m_last_worked_time);
+ m_last_worked_time = get_time();
}
template<class functor_t>
bool do_call(functor_t functr)
{
- time_t current_time = 0;
- time(&current_time);
+ uint64_t current_time = get_time();
if(current_time - m_last_worked_time > m_interval)
{
bool res = functr();
- time(&m_last_worked_time);
+ m_last_worked_time = get_time();
return res;
}
return true;
}
private:
- time_t m_last_worked_time;
- time_t m_interval;
+ uint64_t m_last_worked_time;
+ uint64_t m_interval;
};
+
+ template<int default_interval, bool start_immediate = true>
+ class once_a_time_seconds: public once_a_time<1000000, default_interval, start_immediate> {};
+ template<int default_interval, bool start_immediate = true>
+ class once_a_time_milliseconds: public once_a_time<1000, default_interval, start_immediate> {};
}
}
diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h
index 9100a8db3..1ff9da3a7 100644
--- a/contrib/epee/include/misc_log_ex.h
+++ b/contrib/epee/include/misc_log_ex.h
@@ -38,14 +38,21 @@
#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes
#define MAX_LOG_FILES 50
-#define MCFATAL(cat,x) CLOG(FATAL,cat) << x
-#define MCERROR(cat,x) CLOG(ERROR,cat) << x
-#define MCWARNING(cat,x) CLOG(WARNING,cat) << x
-#define MCINFO(cat,x) CLOG(INFO,cat) << x
-#define MCDEBUG(cat,x) CLOG(DEBUG,cat) << x
-#define MCTRACE(cat,x) CLOG(TRACE,cat) << x
-#define MCLOG(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::NormalLog, cat) << x
-#define MCLOG_FILE(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::FileOnlyLog, cat) << x
+#define MCLOG_TYPE(level, cat, type, x) do { \
+ if (ELPP->vRegistry()->allowed(level, cat)) { \
+ el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \
+ } \
+ } while (0)
+
+#define MCLOG(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::NormalLog, x)
+#define MCLOG_FILE(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::FileOnlyLog, x)
+
+#define MCFATAL(cat,x) MCLOG(el::Level::Fatal,cat, x)
+#define MCERROR(cat,x) MCLOG(el::Level::Error,cat, x)
+#define MCWARNING(cat,x) MCLOG(el::Level::Warning,cat, x)
+#define MCINFO(cat,x) MCLOG(el::Level::Info,cat, x)
+#define MCDEBUG(cat,x) MCLOG(el::Level::Debug,cat, x)
+#define MCTRACE(cat,x) MCLOG(el::Level::Trace,cat, x)
#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,"\033[1;" color "m" << x << "\033[0m")
#define MCLOG_RED(level,cat,x) MCLOG_COLOR(level,cat,"31",x)
diff --git a/contrib/epee/include/net/buffer.h b/contrib/epee/include/net/buffer.h
new file mode 100644
index 000000000..56c67f6bf
--- /dev/null
+++ b/contrib/epee/include/net/buffer.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2018, 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.
+
+#pragma once
+
+#include <vector>
+#include "misc_log_ex.h"
+#include "span.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.buffer"
+
+//#define NET_BUFFER_LOG(x) MDEBUG(x)
+#define NET_BUFFER_LOG(x) ((void)0)
+
+namespace epee
+{
+namespace net_utils
+{
+class buffer
+{
+public:
+ buffer(size_t reserve = 0): offset(0) { storage.reserve(reserve); }
+
+ void append(const void *data, size_t sz);
+ void erase(size_t sz) { NET_BUFFER_LOG("erasing " << sz << "/" << size()); CHECK_AND_ASSERT_THROW_MES(offset + sz <= storage.size(), "erase: sz too large"); offset += sz; if (offset == storage.size()) { storage.resize(0); offset = 0; } }
+ epee::span<const uint8_t> span(size_t sz) const { CHECK_AND_ASSERT_THROW_MES(sz <= size(), "span is too large"); return epee::span<const uint8_t>(storage.data() + offset, sz); }
+ // carve must keep the data in scope till next call, other API calls (such as append, erase) can invalidate the carved buffer
+ epee::span<const uint8_t> carve(size_t sz) { CHECK_AND_ASSERT_THROW_MES(sz <= size(), "span is too large"); offset += sz; return epee::span<const uint8_t>(storage.data() + offset - sz, sz); }
+ size_t size() const { return storage.size() - offset; }
+
+private:
+ std::vector<uint8_t> storage;
+ size_t offset;
+};
+}
+}
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index 997c801d1..64d035df9 100644
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -92,7 +92,7 @@
handled = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
- bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), query_info.m_body); \
+ bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), epee::strspan<uint8_t>(query_info.m_body)); \
CHECK_AND_ASSERT_MES(parse_res, false, "Failed to parse bin body data, body size=" << query_info.m_body.size()); \
uint64_t ticks1 = misc_utils::get_tick_count(); \
boost::value_initialized<command_type::response> resp;\
diff --git a/contrib/epee/include/net/levin_base.h b/contrib/epee/include/net/levin_base.h
index 7d060f5ef..a88a1eb49 100644
--- a/contrib/epee/include/net/levin_base.h
+++ b/contrib/epee/include/net/levin_base.h
@@ -80,8 +80,8 @@ namespace levin
template<class t_connection_context = net_utils::connection_context_base>
struct levin_commands_handler
{
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, t_connection_context& context)=0;
- virtual int notify(int command, const std::string& in_buff, t_connection_context& context)=0;
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, t_connection_context& context)=0;
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, t_connection_context& context)=0;
virtual void callback(t_connection_context& context){};
virtual void on_connection_new(t_connection_context& context){};
diff --git a/contrib/epee/include/net/levin_client.h b/contrib/epee/include/net/levin_client.h
index 335f6ba02..76d528234 100644
--- a/contrib/epee/include/net/levin_client.h
+++ b/contrib/epee/include/net/levin_client.h
@@ -57,7 +57,7 @@ namespace levin
bool is_connected();
bool disconnect();
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out);
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out);
virtual int notify(int command, const std::string& in_buff);
protected:
@@ -72,7 +72,7 @@ namespace levin
{
public:
- int invoke(int command, const std::string& in_buff, std::string& buff_out);
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out);
int notify(int command, const std::string& in_buff);
};
diff --git a/contrib/epee/include/net/levin_client.inl b/contrib/epee/include/net/levin_client.inl
index a580e81fd..2f048b027 100644
--- a/contrib/epee/include/net/levin_client.inl
+++ b/contrib/epee/include/net/levin_client.inl
@@ -74,7 +74,7 @@ levin_client_impl::~levin_client_impl()
}
//------------------------------------------------------------------------------
inline
-int levin_client_impl::invoke(int command, const std::string& in_buff, std::string& buff_out)
+int levin_client_impl::invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out)
{
if(!is_connected())
return -1;
@@ -133,7 +133,7 @@ int levin_client_impl::notify(int command, const std::string& in_buff)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
inline
- int levin_client_impl2::invoke(int command, const std::string& in_buff, std::string& buff_out)
+ int levin_client_impl2::invoke(int command, epee::span<const uint8_t>string& in_buff, std::string& buff_out)
{
if(!is_connected())
return -1;
diff --git a/contrib/epee/include/net/levin_protocol_handler_async.h b/contrib/epee/include/net/levin_protocol_handler_async.h
index 11649febe..a1ea3e680 100644
--- a/contrib/epee/include/net/levin_protocol_handler_async.h
+++ b/contrib/epee/include/net/levin_protocol_handler_async.h
@@ -34,6 +34,7 @@
#include <atomic>
#include "levin_base.h"
+#include "buffer.h"
#include "misc_language.h"
#include "syncobj.h"
#include "misc_os_dependent.h"
@@ -85,11 +86,11 @@ public:
uint64_t m_max_packet_size;
uint64_t m_invoke_timeout;
- int invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
template<class callback_t>
- int invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
+ int invoke_async(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED);
- int notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id);
+ int notify(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id);
bool close(boost::uuids::uuid connection_id);
bool update_connection_context(const t_connection_context& contxt);
bool request_callback(boost::uuids::uuid connection_id);
@@ -143,7 +144,7 @@ public:
config_type& m_config;
t_connection_context& m_connection_context;
- std::string m_cache_in_buffer;
+ net_utils::buffer m_cache_in_buffer;
stream_state m_state;
int32_t m_oponent_protocol_ver;
@@ -151,7 +152,7 @@ public:
struct invoke_response_handler_base
{
- virtual bool handle(int res, const std::string& buff, connection_context& context)=0;
+ virtual bool handle(int res, const epee::span<const uint8_t> buff, connection_context& context)=0;
virtual bool is_timer_started() const=0;
virtual void cancel()=0;
virtual bool cancel_timer()=0;
@@ -173,7 +174,7 @@ public:
if(ec == boost::asio::error::operation_aborted)
return;
MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
- std::string fake;
+ epee::span<const uint8_t> fake;
cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
con.close();
con.finish_outer_call();
@@ -191,7 +192,7 @@ public:
bool m_timer_cancelled;
uint64_t m_timeout;
int m_command;
- virtual bool handle(int res, const std::string& buff, typename async_protocol_handler::connection_context& context)
+ virtual bool handle(int res, const epee::span<const uint8_t> buff, typename async_protocol_handler::connection_context& context)
{
if(!cancel_timer())
return false;
@@ -207,7 +208,7 @@ public:
{
if(cancel_timer())
{
- std::string fake;
+ epee::span<const uint8_t> fake;
m_cb(LEVIN_ERROR_CONNECTION_DESTROYED, fake, m_con.get_context_ref());
m_con.finish_outer_call();
}
@@ -237,7 +238,7 @@ public:
if(ec == boost::asio::error::operation_aborted)
return;
MINFO(con.get_context_ref() << "Timeout on invoke operation happened, command: " << command << " timeout: " << timeout);
- std::string fake;
+ epee::span<const uint8_t> fake;
cb(LEVIN_ERROR_CONNECTION_TIMEDOUT, fake, con.get_context_ref());
con.close();
con.finish_outer_call();
@@ -265,6 +266,7 @@ public:
m_pservice_endpoint(psnd_hndlr),
m_config(config),
m_connection_context(conn_context),
+ m_cache_in_buffer(256 * 1024),
m_state(stream_state_head)
{
m_close_called = 0;
@@ -405,14 +407,7 @@ public:
break;
}
{
- std::string buff_to_invoke;
- if(m_cache_in_buffer.size() == m_current_head.m_cb)
- buff_to_invoke.swap(m_cache_in_buffer);
- else
- {
- buff_to_invoke.assign(m_cache_in_buffer, 0, (std::string::size_type)m_current_head.m_cb);
- m_cache_in_buffer.erase(0, (std::string::size_type)m_current_head.m_cb);
- }
+ epee::span<const uint8_t> buff_to_invoke = m_cache_in_buffer.carve((std::string::size_type)m_current_head.m_cb);
bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE);
@@ -449,8 +444,8 @@ public:
}else
{
CRITICAL_REGION_BEGIN(m_local_inv_buff_lock);
- buff_to_invoke.swap(m_local_inv_buff);
- buff_to_invoke.clear();
+ m_local_inv_buff = std::string((const char*)buff_to_invoke.data(), buff_to_invoke.size());
+ buff_to_invoke = epee::span<const uint8_t>((const uint8_t*)NULL, 0);
m_invoke_result_code = m_current_head.m_return_code;
CRITICAL_REGION_END();
boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 1);
@@ -503,7 +498,7 @@ public:
{
if(m_cache_in_buffer.size() < sizeof(bucket_head2))
{
- if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.data()) != SWAP64LE(LEVIN_SIGNATURE))
+ if(m_cache_in_buffer.size() >= sizeof(uint64_t) && *((uint64_t*)m_cache_in_buffer.span(8).data()) != SWAP64LE(LEVIN_SIGNATURE))
{
MWARNING(m_connection_context << "Signature mismatch, connection will be closed");
return false;
@@ -513,9 +508,9 @@ public:
}
#if BYTE_ORDER == LITTLE_ENDIAN
- bucket_head2& phead = *(bucket_head2*)m_cache_in_buffer.data();
+ bucket_head2& phead = *(bucket_head2*)m_cache_in_buffer.span(sizeof(bucket_head2)).data();
#else
- bucket_head2 phead = *(bucket_head2*)m_cache_in_buffer.data();
+ bucket_head2 phead = *(bucket_head2*)m_cache_in_buffer.span(sizeof(bucket_head2)).data();
phead.m_signature = SWAP64LE(phead.m_signature);
phead.m_cb = SWAP64LE(phead.m_cb);
phead.m_command = SWAP32LE(phead.m_command);
@@ -530,7 +525,7 @@ public:
}
m_current_head = phead;
- m_cache_in_buffer.erase(0, sizeof(bucket_head2));
+ m_cache_in_buffer.erase(sizeof(bucket_head2));
m_state = stream_state_body;
m_oponent_protocol_ver = m_current_head.m_protocol_version;
if(m_current_head.m_cb > m_config.m_max_packet_size)
@@ -562,7 +557,7 @@ public:
}
template<class callback_t>
- bool async_invoke(int command, const std::string& in_buff, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
+ bool async_invoke(int command, const epee::span<const uint8_t> in_buff, const callback_t &cb, size_t timeout = LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler::finish_outer_call, this));
@@ -606,7 +601,7 @@ public:
break;
}
- if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ if(!m_pservice_endpoint->do_send(in_buff.data(), in_buff.size()))
{
LOG_ERROR_CC(m_connection_context, "Failed to do_send");
err_code = LEVIN_ERROR_CONNECTION;
@@ -623,7 +618,7 @@ public:
if (LEVIN_OK != err_code)
{
- std::string stub_buff;
+ epee::span<const uint8_t> stub_buff{(const uint8_t*)"", 0};
// Never call callback inside critical section, that can cause deadlock
cb(err_code, stub_buff, m_connection_context);
return false;
@@ -632,7 +627,7 @@ public:
return true;
}
- int invoke(int command, const std::string& in_buff, std::string& buff_out)
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler::finish_outer_call, this));
@@ -662,7 +657,7 @@ public:
return LEVIN_ERROR_CONNECTION;
}
- if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ if(!m_pservice_endpoint->do_send(in_buff.data(), in_buff.size()))
{
LOG_ERROR_CC(m_connection_context, "Failed to do_send");
return LEVIN_ERROR_CONNECTION;
@@ -706,7 +701,7 @@ public:
return m_invoke_result_code;
}
- int notify(int command, const std::string& in_buff)
+ int notify(int command, const epee::span<const uint8_t> in_buff)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
boost::bind(&async_protocol_handler::finish_outer_call, this));
@@ -734,7 +729,7 @@ public:
return -1;
}
- if(!m_pservice_endpoint->do_send(in_buff.data(), (int)in_buff.size()))
+ if(!m_pservice_endpoint->do_send(in_buff.data(), in_buff.size()))
{
LOG_ERROR_CC(m_connection_context, "Failed to do_send()");
return -1;
@@ -839,7 +834,7 @@ int async_protocol_handler_config<t_connection_context>::find_and_lock_connectio
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
-int async_protocol_handler_config<t_connection_context>::invoke(int command, const std::string& in_buff, std::string& buff_out, boost::uuids::uuid connection_id)
+int async_protocol_handler_config<t_connection_context>::invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, boost::uuids::uuid connection_id)
{
async_protocol_handler<t_connection_context>* aph;
int r = find_and_lock_connection(connection_id, aph);
@@ -847,7 +842,7 @@ int async_protocol_handler_config<t_connection_context>::invoke(int command, con
}
//------------------------------------------------------------------------------------------
template<class t_connection_context> template<class callback_t>
-int async_protocol_handler_config<t_connection_context>::invoke_async(int command, const std::string& in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout)
+int async_protocol_handler_config<t_connection_context>::invoke_async(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id, const callback_t &cb, size_t timeout)
{
async_protocol_handler<t_connection_context>* aph;
int r = find_and_lock_connection(connection_id, aph);
@@ -896,7 +891,7 @@ void async_protocol_handler_config<t_connection_context>::set_handler(levin_comm
}
//------------------------------------------------------------------------------------------
template<class t_connection_context>
-int async_protocol_handler_config<t_connection_context>::notify(int command, const std::string& in_buff, boost::uuids::uuid connection_id)
+int async_protocol_handler_config<t_connection_context>::notify(int command, const epee::span<const uint8_t> in_buff, boost::uuids::uuid connection_id)
{
async_protocol_handler<t_connection_context>* aph;
int r = find_and_lock_connection(connection_id, aph);
diff --git a/contrib/epee/include/span.h b/contrib/epee/include/span.h
index b1296a0b7..cfb5b1a17 100644
--- a/contrib/epee/include/span.h
+++ b/contrib/epee/include/span.h
@@ -163,4 +163,12 @@ namespace epee
static_assert(!has_padding<T>(), "source type may have padding");
return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
+
+ //! make a span from a std::string
+ template<typename T>
+ span<const T> strspan(const std::string &s) noexcept
+ {
+ static_assert(std::is_same<T, char>() || std::is_same<T, unsigned char>() || std::is_same<T, int8_t>() || std::is_same<T, uint8_t>(), "Unexpected type");
+ return {reinterpret_cast<const T*>(s.data()), s.size()};
+ }
}
diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h
index d93084ab0..18b7f10c1 100644
--- a/contrib/epee/include/storages/http_abstract_invoke.h
+++ b/contrib/epee/include/storages/http_abstract_invoke.h
@@ -97,7 +97,7 @@ namespace epee
return false;
}
- return serialization::load_t_from_binary(result_struct, pri->m_body);
+ return serialization::load_t_from_binary(result_struct, epee::strspan<uint8_t>(pri->m_body));
}
template<class t_request, class t_response, class t_transport>
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index d77e7a1f8..06eb9bdaf 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -28,6 +28,7 @@
#include "portable_storage_template_helper.h"
#include <boost/utility/value_init.hpp>
+#include "span.h"
#include "net/levin_base.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -114,7 +115,7 @@ namespace epee
const_cast<t_arg&>(out_struct).store(stg);//TODO: add true const support to searilzation
std::string buff_to_send;
stg.store_to_binary(buff_to_send);
- int res = transport.invoke_async(command, buff_to_send, conn_id, [cb, command](int code, const std::string& buff, typename t_transport::connection_context& context)->bool
+ int res = transport.invoke_async(command, epee::strspan<uint8_t>(buff_to_send), conn_id, [cb, command](int code, const epee::span<const uint8_t> buff, typename t_transport::connection_context& context)->bool
{
t_result result_struct = AUTO_VAL_INIT(result_struct);
if( code <=0 )
@@ -156,7 +157,7 @@ namespace epee
std::string buff_to_send;
stg.store_to_binary(buff_to_send);
- int res = transport.notify(command, buff_to_send, conn_id);
+ int res = transport.notify(command, epee::strspan<uint8_t>(buff_to_send), conn_id);
if(res <=0 )
{
MERROR("Failed to notify command " << command << " return code " << res);
@@ -167,7 +168,7 @@ namespace epee
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
template<class t_owner, class t_in_type, class t_out_type, class t_context, class callback_t>
- int buff_to_t_adapter(int command, const std::string& in_buff, std::string& buff_out, callback_t cb, t_context& context )
+ int buff_to_t_adapter(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, callback_t cb, t_context& context )
{
serialization::portable_storage strg;
if(!strg.load_from_binary(in_buff))
@@ -197,7 +198,7 @@ namespace epee
}
template<class t_owner, class t_in_type, class t_context, class callback_t>
- int buff_to_t_adapter(t_owner* powner, int command, const std::string& in_buff, callback_t cb, t_context& context)
+ int buff_to_t_adapter(t_owner* powner, int command, const epee::span<const uint8_t> in_buff, callback_t cb, t_context& context)
{
serialization::portable_storage strg;
if(!strg.load_from_binary(in_buff))
@@ -215,14 +216,14 @@ namespace epee
}
#define CHAIN_LEVIN_INVOKE_MAP2(context_type) \
- int invoke(int command, const std::string& in_buff, std::string& buff_out, context_type& context) \
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, context_type& context) \
{ \
bool handled = false; \
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
}
#define CHAIN_LEVIN_NOTIFY_MAP2(context_type) \
- int notify(int command, const std::string& in_buff, context_type& context) \
+ int notify(int command, const epee::span<const uint8_t> in_buff, context_type& context) \
{ \
bool handled = false; std::string fake_str;\
return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
@@ -230,27 +231,27 @@ namespace epee
#define CHAIN_LEVIN_INVOKE_MAP() \
- int invoke(int command, const std::string& in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \
+ int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, epee::net_utils::connection_context_base& context) \
{ \
bool handled = false; \
return handle_invoke_map(false, command, in_buff, buff_out, context, handled); \
}
#define CHAIN_LEVIN_NOTIFY_MAP() \
- int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \
+ int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
{ \
bool handled = false; std::string fake_str;\
return handle_invoke_map(true, command, in_buff, fake_str, context, handled); \
}
#define CHAIN_LEVIN_NOTIFY_STUB() \
- int notify(int command, const std::string& in_buff, epee::net_utils::connection_context_base& context) \
+ int notify(int command, const epee::span<const uint8_t> in_buff, epee::net_utils::connection_context_base& context) \
{ \
return -1; \
}
#define BEGIN_INVOKE_MAP2(owner_type) \
- template <class t_context> int handle_invoke_map(bool is_notify, int command, const std::string& in_buff, std::string& buff_out, t_context& context, bool& handled) \
+ template <class t_context> int handle_invoke_map(bool is_notify, int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, t_context& context, bool& handled) \
{ \
typedef owner_type internal_owner_type_name;
diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h
index 31495ae13..d73fbde3a 100644
--- a/contrib/epee/include/storages/parserse_base_utils.h
+++ b/contrib/epee/include/storages/parserse_base_utils.h
@@ -91,11 +91,15 @@ namespace misc_utils
*/
inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
{
- val.clear();
- val.reserve(std::distance(star_end_string, buf_end));
bool escape_mode = false;
std::string::const_iterator it = star_end_string;
++it;
+ std::string::const_iterator fi = it;
+ while (fi != buf_end && *fi != '\\' && *fi != '\"')
+ ++fi;
+ val.assign(it, fi);
+ val.reserve(std::distance(star_end_string, buf_end));
+ it = fi;
for(;it != buf_end;it++)
{
if(escape_mode/*prev_ch == '\\'*/)
diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h
index 0f0c6210f..d0e40d606 100644
--- a/contrib/epee/include/storages/portable_storage.h
+++ b/contrib/epee/include/storages/portable_storage.h
@@ -35,6 +35,7 @@
#include "portable_storage_to_json.h"
#include "portable_storage_from_json.h"
#include "portable_storage_val_converters.h"
+#include "span.h"
#include "int-util.h"
namespace epee
@@ -81,7 +82,8 @@ namespace epee
//-------------------------------------------------------------------------------
bool store_to_binary(binarybuffer& target);
- bool load_from_binary(const binarybuffer& target);
+ bool load_from_binary(const epee::span<const uint8_t> target);
+ bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan<uint8_t>(target)); }
template<class trace_policy>
bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
bool dump_as_json(std::string& targetObj, size_t indent = 0, bool insert_newlines = true);
@@ -146,7 +148,7 @@ namespace epee
CATCH_ENTRY("portable_storage::store_to_binary", false)
}
inline
- bool portable_storage::load_from_binary(const binarybuffer& source)
+ bool portable_storage::load_from_binary(const epee::span<const uint8_t> source)
{
m_root.m_entries.clear();
if(source.size() < sizeof(storage_block_header))
diff --git a/contrib/epee/include/storages/portable_storage_base.h b/contrib/epee/include/storages/portable_storage_base.h
index 93132548b..da84fd8ea 100644
--- a/contrib/epee/include/storages/portable_storage_base.h
+++ b/contrib/epee/include/storages/portable_storage_base.h
@@ -31,7 +31,8 @@
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <string>
-#include <list>
+#include <vector>
+#include <deque>
#define PORTABLE_STORAGE_SIGNATUREA 0x01011101
#define PORTABLE_STORAGE_SIGNATUREB 0x01020101 // bender's nightmare
@@ -71,6 +72,9 @@ namespace epee
{
struct section;
+ template<typename T> struct entry_container { typedef std::vector<T> type; static void reserve(type &t, size_t n) { t.reserve(n); } };
+ template<> struct entry_container<bool> { typedef std::deque<bool> type; static void reserve(type &t, size_t n) {} };
+
/************************************************************************/
/* */
/************************************************************************/
@@ -119,8 +123,13 @@ namespace epee
return m_array.back();
}
- std::list<t_entry_type> m_array;
- mutable typename std::list<t_entry_type>::const_iterator m_it;
+ void reserve(size_t n)
+ {
+ entry_container<t_entry_type>::reserve(m_array, n);
+ }
+
+ typename entry_container<t_entry_type>::type m_array;
+ mutable typename entry_container<t_entry_type>::type::const_iterator m_it;
};
diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h
index f9cc22d27..2884f8c5e 100644
--- a/contrib/epee/include/storages/portable_storage_from_bin.h
+++ b/contrib/epee/include/storages/portable_storage_from_bin.h
@@ -136,6 +136,7 @@ namespace epee
//for pod types
array_entry_t<type_name> sa;
size_t size = read_varint();
+ sa.reserve(size);
//TODO: add some optimization here later
while(size--)
sa.m_array.push_back(read<type_name>());
diff --git a/contrib/epee/include/storages/portable_storage_template_helper.h b/contrib/epee/include/storages/portable_storage_template_helper.h
index bbd8413fc..13c870d44 100644
--- a/contrib/epee/include/storages/portable_storage_template_helper.h
+++ b/contrib/epee/include/storages/portable_storage_template_helper.h
@@ -84,7 +84,7 @@ namespace epee
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
- bool load_t_from_binary(t_struct& out, const std::string& binary_buff)
+ bool load_t_from_binary(t_struct& out, const epee::span<const uint8_t> binary_buff)
{
portable_storage ps;
bool rs = ps.load_from_binary(binary_buff);
@@ -95,6 +95,12 @@ namespace epee
}
//-----------------------------------------------------------------------------------------------------------
template<class t_struct>
+ bool load_t_from_binary(t_struct& out, const std::string& binary_buff)
+ {
+ return load_t_from_binary(out, epee::strspan<uint8_t>(binary_buff));
+ }
+ //-----------------------------------------------------------------------------------------------------------
+ template<class t_struct>
bool load_t_from_binary_file(t_struct& out, const std::string& binary_file)
{
std::string f_buff;
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index 6a063cc36..f7539fb6c 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -40,8 +40,6 @@
#include <cstdlib>
#include <string>
#include <type_traits>
-#include <boost/uuid/uuid.hpp>
-#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include "hex.h"
@@ -83,50 +81,18 @@ namespace epee
{
namespace string_tools
{
- //----------------------------------------------------------------------------
- inline std::string get_str_from_guid_a(const boost::uuids::uuid& rid)
- {
- return boost::lexical_cast<std::string>(rid);
- }
- //----------------------------------------------------------------------------
- inline bool get_guid_from_string(OUT boost::uuids::uuid& inetifer, const std::string& str_id)
- {
- std::string local_str_id = str_id;
- if(local_str_id.size() < 36)
- return false;
-
- if('{' == *local_str_id.begin())
- local_str_id.erase(0, 1);
-
- if('}' == *(--local_str_id.end()))
- local_str_id.erase(--local_str_id.end());
-
- try
- {
- inetifer = boost::lexical_cast<boost::uuids::uuid>(local_str_id);
- return true;
- }
- catch(...)
- {
- return false;
- }
- }
//----------------------------------------------------------------------------
inline std::string buff_to_hex_nodelimer(const std::string& src)
{
return to_hex::string(to_byte_span(to_span(src)));
}
//----------------------------------------------------------------------------
- template<class CharT>
- bool parse_hexstr_to_binbuff(const std::basic_string<CharT>& s, std::basic_string<CharT>& res)
+ inline bool parse_hexstr_to_binbuff(const epee::span<const char> s, epee::span<char>& res)
{
- res.clear();
- if (s.size() & 1)
- return false;
- try
- {
- res.resize(s.size() / 2);
- unsigned char *dst = (unsigned char *)res.data();
+ if (s.size() != res.size() * 2)
+ return false;
+
+ unsigned char *dst = (unsigned char *)&res[0];
const unsigned char *src = (const unsigned char *)s.data();
for(size_t i = 0; i < s.size(); i += 2)
{
@@ -140,28 +106,15 @@ namespace string_tools
}
return true;
- }
- catch(...)
- {
- return false;
- }
}
//----------------------------------------------------------------------------
- template<class t_pod_type>
- bool parse_tpod_from_hex_string(const std::string& str_hash, t_pod_type& t_pod)
+ inline bool parse_hexstr_to_binbuff(const std::string& s, std::string& res)
{
- static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
- std::string buf;
- bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
- if (!res || buf.size() != sizeof(t_pod_type))
- {
+ if (s.size() & 1)
return false;
- }
- else
- {
- buf.copy(reinterpret_cast<char *>(&t_pod), sizeof(t_pod_type));
- return true;
- }
+ res.resize(s.size() / 2);
+ epee::span<char> rspan((char*)&res[0], res.size());
+ return parse_hexstr_to_binbuff(epee::to_span(s), rspan);
}
//----------------------------------------------------------------------------
PUSH_WARNINGS
@@ -360,17 +313,10 @@ POP_WARNINGS
bool hex_to_pod(const std::string& hex_str, t_pod_type& s)
{
static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
- std::string hex_str_tr = trim(hex_str);
if(sizeof(s)*2 != hex_str.size())
return false;
- std::string bin_buff;
- if(!parse_hexstr_to_binbuff(hex_str_tr, bin_buff))
- return false;
- if(bin_buff.size()!=sizeof(s))
- return false;
-
- s = *(t_pod_type*)bin_buff.data();
- return true;
+ epee::span<char> rspan((char*)&s, sizeof(s));
+ return parse_hexstr_to_binbuff(epee::to_span(hex_str), rspan);
}
//----------------------------------------------------------------------------
template<class t_pod_type>
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index bc437deb9..cea50c9dd 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -27,7 +27,7 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c
- connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp)
+ connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp mlocker.cpp buffer.cpp)
if (USE_READLINE AND GNU_READLINE_FOUND)
add_library(epee_readline STATIC readline_buffer.cpp)
endif()
diff --git a/contrib/epee/src/buffer.cpp b/contrib/epee/src/buffer.cpp
new file mode 100644
index 000000000..d637b905e
--- /dev/null
+++ b/contrib/epee/src/buffer.cpp
@@ -0,0 +1,97 @@
+// Copyright (c) 2018, 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.
+
+#include <string.h>
+#include "net/buffer.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "net.buffer"
+
+namespace epee
+{
+namespace net_utils
+{
+
+void buffer::append(const void *data, size_t sz)
+{
+ const size_t capacity = storage.capacity();
+ const size_t avail = capacity - storage.size();
+
+ CHECK_AND_ASSERT_THROW_MES(storage.size() < std::numeric_limits<size_t>::max() - sz, "Too much data to append");
+
+ // decide when to move
+ if (sz > avail)
+ {
+ // we have to reallocate or move
+ const bool move = size() + sz <= capacity;
+ if (move)
+ {
+ const size_t bytes = storage.size() - offset;
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by moving " << bytes << " from offset " << offset << " first (forced)");
+ memmove(storage.data(), storage.data() + offset, bytes);
+ storage.resize(bytes);
+ offset = 0;
+ }
+ else
+ {
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by reallocating");
+ std::vector<uint8_t> new_storage;
+ size_t reserve = (((size() + sz) * 3 / 2) + 4095) & ~4095;
+ new_storage.reserve(reserve);
+ new_storage.resize(size());
+ memcpy(new_storage.data(), storage.data() + offset, storage.size() - offset);
+ offset = 0;
+ std::swap(storage, new_storage);
+ }
+ }
+ else
+ {
+ // we have space already
+ if (size() <= 4096 && offset > 4096 * 16 && offset >= capacity / 2)
+ {
+ // we have little to move, and we're far enough into the buffer that it's probably a win to move anyway
+ const size_t pos = storage.size() - offset;
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by moving " << pos << " from offset " << offset << " first (unforced)");
+ memmove(storage.data(), storage.data() + offset, storage.size() - offset);
+ storage.resize(pos);
+ offset = 0;
+ }
+ else
+ {
+ NET_BUFFER_LOG("appending " << sz << " from " << size() << " by writing to existing capacity");
+ }
+ }
+
+ // add the new data
+ storage.insert(storage.end(), (const uint8_t*)data, (const uint8_t*)data + sz);
+
+ NET_BUFFER_LOG("storage now " << offset << "/" << storage.size() << "/" << storage.capacity());
+}
+
+}
+}
diff --git a/contrib/epee/src/mlocker.cpp b/contrib/epee/src/mlocker.cpp
index 078a84ce3..446fa3315 100644
--- a/contrib/epee/src/mlocker.cpp
+++ b/contrib/epee/src/mlocker.cpp
@@ -40,6 +40,9 @@
#include <atomic>
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "mlocker"
+
// did an mlock operation previously fail? we only
// want to log an error once and be done with it
static std::atomic<bool> previously_failed{ false };
diff --git a/contrib/epee/src/net_utils_base.cpp b/contrib/epee/src/net_utils_base.cpp
index 354c3d2c3..263b344b4 100644
--- a/contrib/epee/src/net_utils_base.cpp
+++ b/contrib/epee/src/net_utils_base.cpp
@@ -1,7 +1,9 @@
#include "net/net_utils_base.h"
-#include "string_tools.h"
+#include <boost/uuid/uuid_io.hpp>
+
+#include "string_tools.h"
#include "net/local_ip.h"
namespace epee { namespace net_utils
@@ -73,7 +75,7 @@ namespace epee { namespace net_utils
std::string print_connection_context(const connection_context_base& ctx)
{
std::stringstream ss;
- ss << ctx.m_remote_address.str() << " " << epee::string_tools::get_str_from_guid_a(ctx.m_connection_id) << (ctx.m_is_income ? " INC":" OUT");
+ ss << ctx.m_remote_address.str() << " " << ctx.m_connection_id << (ctx.m_is_income ? " INC":" OUT");
return ss.str();
}
diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc
index ab4ee49c3..f5f7481f8 100644
--- a/external/easylogging++/easylogging++.cc
+++ b/external/easylogging++/easylogging++.cc
@@ -2693,6 +2693,12 @@ Writer& Writer::construct(int count, const char* loggerIds, ...) {
return *this;
}
+Writer& Writer::construct(const char *loggerId) {
+ initializeLogger(ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)));
+ m_messageBuilder.initialize(m_logger);
+ return *this;
+}
+
void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) {
if (lookup) {
m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
@@ -2721,6 +2727,19 @@ void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool nee
}
}
+void Writer::initializeLogger(Logger *logger, bool needLock) {
+ m_logger = logger;
+ if (m_logger == nullptr) {
+ m_proceed = false;
+ } else {
+ if (needLock) {
+ m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because
+ // m_proceed can be changed by lines below
+ }
+ m_proceed = true;
+ }
+}
+
void Writer::processDispatch() {
#if ELPP_LOGGING_ENABLED
if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h
index 1e27f62a6..d9a2dc3d1 100644
--- a/external/easylogging++/easylogging++.h
+++ b/external/easylogging++/easylogging++.h
@@ -3290,6 +3290,7 @@ class Writer : base::NoCopy {
Writer& construct(Logger* logger, bool needLock = true);
Writer& construct(int count, const char* loggerIds, ...);
+ Writer& construct(const char *loggerId);
protected:
LogMessage* m_msg;
Level m_level;
@@ -3305,6 +3306,7 @@ class Writer : base::NoCopy {
friend class el::Helpers;
void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true);
+ void initializeLogger(Logger *logger, bool needLock = true);
void processDispatch();
void triggerDispatch(void);
};
diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp
index b27a00a69..60a7326f8 100644
--- a/src/blockchain_db/berkeleydb/db_bdb.cpp
+++ b/src/blockchain_db/berkeleydb/db_bdb.cpp
@@ -1632,7 +1632,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& global_index) const
return v;
}
-output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index)
+output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
check_open();
@@ -1641,7 +1641,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64
return get_output_key(glob_index);
}
-tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index)
+tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
std::vector < uint64_t > offsets;
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index f13aa0cae..5c80bfe4a 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1258,7 +1258,7 @@ public:
*
* @return the requested output data
*/
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0;
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const = 0;
/**
* @brief gets an output's tx hash and index
@@ -1310,7 +1310,7 @@ public:
* @param offsets a list of amount-specific output indices
* @param outputs return-by-reference a list of outputs' metadata
*/
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) = 0;
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const = 0;
/*
* FIXME: Need to check with git blame and ask what this does to
@@ -1329,10 +1329,11 @@ public:
* If an output cannot be found, the subclass should throw OUTPUT_DNE.
*
* @param tx_id a transaction ID
+ * @param n_txes how many txes to get data for, starting with tx_id
*
* @return a list of amount-specific output indices
*/
- virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_id) const = 0;
+ virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes = 1) const = 0;
/**
* @brief check if a key image is stored as spent
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index acda777f9..833d6bd05 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -1025,7 +1025,8 @@ void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_id, const transaction&
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- std::vector<uint64_t> amount_output_indices = get_tx_amount_output_indices(tx_id);
+ std::vector<std::vector<uint64_t>> amount_output_indices_set = get_tx_amount_output_indices(tx_id, 1);
+ const std::vector<uint64_t> &amount_output_indices = amount_output_indices_set.front();
if (amount_output_indices.empty())
{
@@ -2535,7 +2536,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
return num_elems;
}
-output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index)
+output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -2604,7 +2605,7 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, con
return indices[0];
}
-std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const uint64_t tx_id) const
+std::vector<std::vector<uint64_t>> BlockchainLMDB::get_tx_amount_output_indices(uint64_t tx_id, size_t n_txes) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2613,35 +2614,40 @@ std::vector<uint64_t> BlockchainLMDB::get_tx_amount_output_indices(const uint64_
TXN_PREFIX_RDONLY();
RCURSOR(tx_outputs);
- int result = 0;
MDB_val_set(k_tx_id, tx_id);
MDB_val v;
- std::vector<uint64_t> amount_output_indices;
+ std::vector<std::vector<uint64_t>> amount_output_indices_set;
+ amount_output_indices_set.reserve(n_txes);
- result = mdb_cursor_get(m_cur_tx_outputs, &k_tx_id, &v, MDB_SET);
- if (result == MDB_NOTFOUND)
- LOG_PRINT_L0("WARNING: Unexpected: tx has no amount indices stored in "
- "tx_outputs, but it should have an empty entry even if it's a tx without "
- "outputs");
- else if (result)
- throw0(DB_ERROR(lmdb_error("DB error attempting to get data for tx_outputs[tx_index]", result).c_str()));
+ MDB_cursor_op op = MDB_SET;
+ while (n_txes-- > 0)
+ {
+ int result = mdb_cursor_get(m_cur_tx_outputs, &k_tx_id, &v, op);
+ if (result == MDB_NOTFOUND)
+ LOG_PRINT_L0("WARNING: Unexpected: tx has no amount indices stored in "
+ "tx_outputs, but it should have an empty entry even if it's a tx without "
+ "outputs");
+ else if (result)
+ throw0(DB_ERROR(lmdb_error("DB error attempting to get data for tx_outputs[tx_index]", result).c_str()));
- const uint64_t* indices = (const uint64_t*)v.mv_data;
- int num_outputs = v.mv_size / sizeof(uint64_t);
+ op = MDB_NEXT;
- amount_output_indices.reserve(num_outputs);
- for (int i = 0; i < num_outputs; ++i)
- {
- // LOG_PRINT_L0("amount output index[" << 2*i << "]" << ": " << paired_indices[2*i] << " global output index: " << paired_indices[2*i+1]);
- amount_output_indices.push_back(indices[i]);
+ const uint64_t* indices = (const uint64_t*)v.mv_data;
+ size_t num_outputs = v.mv_size / sizeof(uint64_t);
+
+ amount_output_indices_set.resize(amount_output_indices_set.size() + 1);
+ std::vector<uint64_t> &amount_output_indices = amount_output_indices_set.back();
+ amount_output_indices.reserve(num_outputs);
+ for (size_t i = 0; i < num_outputs; ++i)
+ {
+ amount_output_indices.push_back(indices[i]);
+ }
}
- indices = nullptr;
TXN_POSTFIX_RDONLY();
- return amount_output_indices;
+ return amount_output_indices_set;
}
-
bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -3242,7 +3248,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_POSTFIX_RDONLY();
}
-void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial)
+void BlockchainLMDB::get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial) const
{
if (amounts.size() != 1 && amounts.size() != offsets.size())
throw0(DB_ERROR("Invalid sizes of amounts and offets"));
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index b7b1b04d5..3e6e754d2 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -242,8 +242,8 @@ public:
virtual uint64_t get_num_outputs(const uint64_t& amount) const;
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index);
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false);
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const;
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const;
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@@ -252,7 +252,7 @@ public:
virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const;
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<tx_out_index> &indices) const;
- virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_id) const;
+ virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes) const;
virtual bool has_key_image(const crypto::key_image& img) const;
diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp
index 73819bd25..8b007e901 100644
--- a/src/blockchain_utilities/blockchain_blackball.cpp
+++ b/src/blockchain_utilities/blockchain_blackball.cpp
@@ -1131,7 +1131,7 @@ int main(int argc, char* argv[])
return 1;
}
- mlog_configure(mlog_get_default_log_path("monero-blockchain-find-spent-outputs.log"), true);
+ mlog_configure(mlog_get_default_log_path("monero-blockchain-mark-spent-outputs.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
diff --git a/src/blocks/CMakeLists.txt b/src/blocks/CMakeLists.txt
index 30d85adbf..ff48af6dc 100644
--- a/src/blocks/CMakeLists.txt
+++ b/src/blocks/CMakeLists.txt
@@ -39,7 +39,7 @@ foreach(BLOB_NAME checkpoints testnet_blocks stagenet_blocks)
cd ${CMAKE_CURRENT_BINARY_DIR} &&
echo "'#include\t<stddef.h>'" > ${OUTPUT_C_SOURCE} &&
echo "'const\tunsigned\tchar\t${BLOB_NAME}[]={'" >> ${OUTPUT_C_SOURCE} &&
- od -v -An -tu1 ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_DAT_FILE} | sed -e "'s/[0-9]\\{1,\\}/&,/g'" -e "'$$s/.$$//'" >> ${OUTPUT_C_SOURCE} &&
+ od -v -An -tx1 ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_DAT_FILE} | sed -e "'s/[0-9a-fA-F]\\{1,\\}/0x&,/g'" -e "'$$s/.$$//'" >> ${OUTPUT_C_SOURCE} &&
echo "'};'" >> ${OUTPUT_C_SOURCE} &&
echo "'const\tsize_t\t${BLOB_NAME}_len\t=\tsizeof(${BLOB_NAME});'" >> ${OUTPUT_C_SOURCE}
)
diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp
index 1807d44d9..96f575b2d 100644
--- a/src/checkpoints/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -74,7 +74,7 @@ namespace cryptonote
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
{
crypto::hash h = crypto::null_hash;
- bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h);
+ bool r = epee::string_tools::hex_to_pod(hash_str, h);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!");
// return false if adding at a height we already have AND the hash is different
@@ -292,7 +292,7 @@ namespace cryptonote
// parse the second part as crypto::hash,
// if this fails move on to the next record
std::string hashStr = record.substr(pos + 1);
- if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash))
+ if (!epee::string_tools::hex_to_pod(hashStr, hash))
{
continue;
}
diff --git a/src/common/perf_timer.cpp b/src/common/perf_timer.cpp
index d9f1f65c1..3e1357833 100644
--- a/src/common/perf_timer.cpp
+++ b/src/common/perf_timer.cpp
@@ -33,6 +33,13 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "perf"
+#define PERF_LOG_ALWAYS(level, cat, x) \
+ el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::FileOnlyLog).construct(cat) << x
+#define PERF_LOG(level, cat, x) \
+ do { \
+ if (ELPP->vRegistry()->allowed(level, cat)) PERF_LOG_ALWAYS(level, cat, x); \
+ } while(0)
+
namespace tools
{
uint64_t get_tick_count()
@@ -106,9 +113,11 @@ PerformanceTimer::PerformanceTimer(bool paused): started(true), paused(paused)
LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l): PerformanceTimer(), name(s), cat(cat), unit(unit), level(l)
{
+ const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
if (!performance_timers)
{
- MCLOG(level, cat.c_str(), "PERF ----------");
+ if (log)
+ PERF_LOG_ALWAYS(level, cat.c_str(), "PERF ----------");
performance_timers = new std::vector<LoggingPerformanceTimer*>();
performance_timers->reserve(16); // how deep before realloc
}
@@ -117,8 +126,11 @@ LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std
LoggingPerformanceTimer *pt = performance_timers->back();
if (!pt->started && !pt->paused)
{
- size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
- MCLOG(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name);
+ if (log)
+ {
+ size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
+ PERF_LOG_ALWAYS(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name);
+ }
pt->started = true;
}
}
@@ -135,10 +147,14 @@ LoggingPerformanceTimer::~LoggingPerformanceTimer()
{
pause();
performance_timers->pop_back();
- char s[12];
- snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
- size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
- MCLOG(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name);
+ const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
+ if (log)
+ {
+ char s[12];
+ snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
+ size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
+ PERF_LOG_ALWAYS(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name);
+ }
if (performance_timers->empty())
{
delete performance_timers;
@@ -162,4 +178,20 @@ void PerformanceTimer::resume()
paused = false;
}
+void PerformanceTimer::reset()
+{
+ if (paused)
+ ticks = 0;
+ else
+ ticks = get_tick_count();
+}
+
+uint64_t PerformanceTimer::value() const
+{
+ uint64_t v = ticks;
+ if (!paused)
+ v = get_tick_count() - v;
+ return ticks_to_ns(v);
+}
+
}
diff --git a/src/common/perf_timer.h b/src/common/perf_timer.h
index 267f94161..d859cf576 100644
--- a/src/common/perf_timer.h
+++ b/src/common/perf_timer.h
@@ -51,8 +51,8 @@ public:
~PerformanceTimer();
void pause();
void resume();
-
- uint64_t value() const { return ticks; }
+ void reset();
+ uint64_t value() const;
protected:
uint64_t ticks;
diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
index 87a394918..447d79aee 100644
--- a/src/cryptonote_basic/hardfork.cpp
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -222,7 +222,6 @@ bool HardFork::reorganize_from_block_height(uint64_t height)
if (height >= db.height())
return false;
- db.set_batch_transactions(true);
bool stop_batch = db.batch_start();
versions.clear();
@@ -306,6 +305,29 @@ bool HardFork::rescan_from_chain_height(uint64_t height)
return rescan_from_block_height(height - 1);
}
+void HardFork::on_block_popped(uint64_t nblocks)
+{
+ CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "nblocks must be greater than 0");
+
+ CRITICAL_REGION_LOCAL(lock);
+
+ const uint64_t new_chain_height = db.height();
+ const uint64_t old_chain_height = new_chain_height + nblocks;
+ uint8_t version;
+ uint64_t height;
+ for (height = old_chain_height - 1; height >= new_chain_height; --height)
+ {
+ versions.pop_back();
+ version = db.get_hard_fork_version(height);
+ versions.push_front(version);
+ }
+
+ // does not take voting into account
+ for (current_fork_index = heights.size() - 1; current_fork_index > 0; --current_fork_index)
+ if (height >= heights[current_fork_index].height)
+ break;
+}
+
int HardFork::get_voted_fork_index(uint64_t height) const
{
CRITICAL_REGION_LOCAL(lock);
diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h
index a63a66976..a3fc25dfa 100644
--- a/src/cryptonote_basic/hardfork.h
+++ b/src/cryptonote_basic/hardfork.h
@@ -150,6 +150,16 @@ namespace cryptonote
bool reorganize_from_chain_height(uint64_t height);
/**
+ * @brief called when one or more blocks are popped from the blockchain
+ *
+ * The current fork will be updated by looking up the db,
+ * which is much cheaper than recomputing everything
+ *
+ * @param new_chain_height the height of the chain after popping
+ */
+ void on_block_popped(uint64_t new_chain_height);
+
+ /**
* @brief returns current state at the given time
*
* Based on the approximate time of the last known hard fork,
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index bbac20eaa..d8163721e 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -641,6 +641,9 @@ block Blockchain::pop_block_from_blockchain()
throw;
}
+ // make sure the hard fork object updates its current version
+ m_hardfork->on_block_popped(1);
+
// return transactions from popped block to the tx_pool
for (transaction& tx : popped_txs)
{
@@ -651,12 +654,7 @@ block Blockchain::pop_block_from_blockchain()
// FIXME: HardFork
// Besides the below, popping a block should also remove the last entry
// in hf_versions.
- //
- // FIXME: HardFork
- // This is not quite correct, as we really want to add the txes
- // to the pool based on the version determined after all blocks
- // are popped.
- uint8_t version = get_current_hard_fork_version();
+ uint8_t version = get_ideal_hard_fork_version(m_db->height());
// We assume that if they were in a block, the transactions are already
// known to the network as a whole. However, if we had mined that block,
@@ -921,8 +919,10 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
//------------------------------------------------------------------
std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
{
- std::vector<time_t> timestamps(blocks);
uint64_t height = m_db->height();
+ if (blocks > height)
+ blocks = height;
+ std::vector<time_t> timestamps(blocks);
while (blocks--)
timestamps[blocks] = m_db->get_block_timestamp(height - blocks - 1);
return timestamps;
@@ -1199,7 +1199,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
return false;
}
// From hard fork 2, we allow a miner to claim less block reward than is allowed, in case a miner wants less dust
- if (m_hardfork->get_current_version() < 2)
+ if (version < 2)
{
if(base_reward + fee != money_in_use)
{
@@ -2298,7 +2298,7 @@ bool Blockchain::check_for_double_spend(const transaction& tx, key_images_contai
return true;
}
//------------------------------------------------------------------
-bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const
+bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2308,16 +2308,25 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<u
MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
return false;
}
+ indexs = m_db->get_tx_amount_output_indices(tx_index, n_txes);
+ CHECK_AND_ASSERT_MES(n_txes == indexs.size(), false, "Wrong indexs size");
- // get amount output indexes, currently referred to in parts as "output global indices", but they are actually specific to amounts
- indexs = m_db->get_tx_amount_output_indices(tx_index);
- if (indexs.empty())
+ return true;
+}
+//------------------------------------------------------------------
+bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const
+{
+ LOG_PRINT_L3("Blockchain::" << __func__);
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
+ uint64_t tx_index;
+ if (!m_db->tx_exists(tx_id, tx_index))
{
- // empty indexs is only valid if the vout is empty, which is legal but rare
- cryptonote::transaction tx = m_db->get_tx(tx_id);
- CHECK_AND_ASSERT_MES(tx.vout.empty(), false, "internal error: global indexes for transaction " << tx_id << " is empty, and tx vout is not");
+ MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
+ return false;
}
-
+ std::vector<std::vector<uint64_t>> indices = m_db->get_tx_amount_output_indices(tx_index, 1);
+ CHECK_AND_ASSERT_MES(indices.size() == 1, false, "Wrong indices size");
+ indexs = indices.front();
return true;
}
//------------------------------------------------------------------
@@ -3842,33 +3851,11 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
}
//------------------------------------------------------------------
-void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, const std::vector<output_data_t> &extra_tx_map) const
+void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs) const
{
try
{
m_db->get_output_key(epee::span<const uint64_t>(&amount, 1), offsets, outputs, true);
- if (outputs.size() < offsets.size())
- {
- const uint64_t n_outputs = m_db->get_num_outputs(amount);
- for (size_t i = outputs.size(); i < offsets.size(); ++i)
- {
- uint64_t idx = offsets[i];
- if (idx < n_outputs)
- {
- MWARNING("Index " << idx << " not found in db for amount " << amount << ", but it is less than the number of entries");
- break;
- }
- else if (idx < n_outputs + extra_tx_map.size())
- {
- outputs.push_back(extra_tx_map[idx - n_outputs]);
- }
- else
- {
- MWARNING("missed " << amount << "/" << idx << " in " << extra_tx_map.size() << " (chain " << n_outputs << ")");
- break;
- }
- }
- }
}
catch (const std::exception& e)
{
@@ -3983,34 +3970,6 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
// vs [k_image, output_keys] (m_scan_table). This is faster because it takes advantage of bulk queries
// and is threaded if possible. The table (m_scan_table) will be used later when querying output
// keys.
-static bool update_output_map(std::map<uint64_t, std::vector<output_data_t>> &extra_tx_map, const transaction &tx, uint64_t height, bool miner)
-{
- MTRACE("Blockchain::" << __func__);
- for (size_t i = 0; i < tx.vout.size(); ++i)
- {
- const auto &out = tx.vout[i];
- if (out.target.type() != typeid(txout_to_key))
- continue;
- const txout_to_key &out_to_key = boost::get<txout_to_key>(out.target);
- rct::key commitment;
- uint64_t amount = out.amount;
- if (miner && tx.version == 2)
- {
- commitment = rct::zeroCommit(amount);
- amount = 0;
- }
- else if (tx.version > 1)
- {
- CHECK_AND_ASSERT_MES(i < tx.rct_signatures.outPk.size(), false, "Invalid outPk size");
- commitment = tx.rct_signatures.outPk[i].mask;
- }
- else
- commitment = rct::zero();
- extra_tx_map[amount].push_back(output_data_t{out_to_key.key, tx.unlock_time, height, commitment});
- }
- return true;
-}
-
bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks_entry)
{
MTRACE("Blockchain::" << __func__);
@@ -4179,7 +4138,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
// [input] stores all absolute_offsets for each amount
std::map<uint64_t, std::vector<uint64_t>> offset_map;
// [output] stores all output_data_t for each absolute_offset
- std::map<uint64_t, std::vector<output_data_t>> tx_map, extra_tx_map;
+ std::map<uint64_t, std::vector<output_data_t>> tx_map;
std::vector<std::pair<cryptonote::transaction, crypto::hash>> txes(total_txs);
#define SCAN_TABLE_QUIT(m) \
@@ -4196,8 +4155,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
if (m_cancel)
return false;
- if (!update_output_map(extra_tx_map, blocks[block_index].miner_tx, height + block_index, true))
- SCAN_TABLE_QUIT("Error building extra tx map.");
for (const auto &tx_blob : entry.txs)
{
if (tx_index >= txes.size())
@@ -4256,8 +4213,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
offset_map[in_to_key.amount].push_back(offset);
}
- if (!update_output_map(extra_tx_map, tx, height + block_index, false))
- SCAN_TABLE_QUIT("Error building extra tx map.");
}
++block_index;
}
@@ -4282,7 +4237,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
for (size_t i = 0; i < amounts.size(); i++)
{
uint64_t amount = amounts[i];
- tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount]), std::cref(extra_tx_map[amount])), true);
+ tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount])), true);
}
waiter.wait(&tpool);
}
@@ -4291,7 +4246,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
for (size_t i = 0; i < amounts.size(); i++)
{
uint64_t amount = amounts[i];
- output_scan_worker(amount, offset_map[amount], tx_map[amount], extra_tx_map[amount]);
+ output_scan_worker(amount, offset_map[amount], tx_map[amount]);
}
}
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 67bccc6c6..5a1c4b9ad 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -521,10 +521,12 @@ namespace cryptonote
*
* @param tx_id the hash of the transaction to fetch indices for
* @param indexs return-by-reference the global indices for the transaction's outputs
+ * @param n_txes how many txes in a row to get results for
*
* @return false if the transaction does not exist, or if no indices are found, otherwise true
*/
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const;
+ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const;
/**
* @brief stores the blockchain
@@ -923,7 +925,7 @@ namespace cryptonote
* @param outputs return-by-reference the outputs collected
*/
void output_scan_worker(const uint64_t amount,const std::vector<uint64_t> &offsets,
- std::vector<output_data_t> &outputs, const std::vector<output_data_t> &extra_tx_map) const;
+ std::vector<output_data_t> &outputs) const;
/**
* @brief computes the "short" and "long" hashes for a set of blocks
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index f3249ea92..1fa6969a6 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1220,6 +1220,11 @@ namespace cryptonote
return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs);
}
//-----------------------------------------------------------------------------------------------
+ bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const
+ {
+ return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, n_txes, indexs);
+ }
+ //-----------------------------------------------------------------------------------------------
void core::pause_mine()
{
m_miner.pause();
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index cc53fce58..fe86f8d39 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -534,6 +534,7 @@ namespace cryptonote
* @note see Blockchain::get_tx_outputs_gindexs
*/
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const;
+ bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const;
/**
* @copydoc Blockchain::get_tail_id
diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp
index 05f4189fb..c1989f093 100644
--- a/src/cryptonote_protocol/block_queue.cpp
+++ b/src/cryptonote_protocol/block_queue.cpp
@@ -31,6 +31,7 @@
#include <vector>
#include <unordered_map>
#include <boost/uuid/nil_generator.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include "string_tools.h"
#include "cryptonote_protocol_defs.h"
#include "block_queue.h"
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index d7b74c06d..3c5b22b4a 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -131,6 +131,7 @@ namespace cryptonote
bool should_download_next_span(cryptonote_connection_context& context) const;
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
bool kick_idle_peers();
+ bool check_standby_peers();
int try_add_next_blocks(cryptonote_connection_context &context);
t_core& m_core;
@@ -143,6 +144,7 @@ namespace cryptonote
boost::mutex m_sync_lock;
block_queue m_block_queue;
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
+ epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
boost::mutex m_buffer_mutex;
double get_avg_block_size();
@@ -155,7 +157,7 @@ namespace cryptonote
std::string blob;
epee::serialization::store_t_to_binary(arg, blob);
//handler_response_blocks_now(blob.size()); // XXX
- return m_p2p->invoke_notify_to_peer(t_parameter::ID, blob, context);
+ return m_p2p->invoke_notify_to_peer(t_parameter::ID, epee::strspan<uint8_t>(blob), context);
}
template<class t_parameter>
@@ -164,7 +166,7 @@ namespace cryptonote
LOG_PRINT_L2("[" << epee::net_utils::print_connection_context_short(exclude_context) << "] post relay " << typeid(t_parameter).name() << " -->");
std::string arg_buff;
epee::serialization::store_t_to_binary(arg, arg_buff);
- return m_p2p->relay_notify_to_all(t_parameter::ID, arg_buff, exclude_context);
+ return m_p2p->relay_notify_to_all(t_parameter::ID, epee::strspan<uint8_t>(arg_buff), exclude_context);
}
};
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 1de0cde07..01f70cba1 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -1210,6 +1210,7 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::on_idle()
{
m_idle_peer_kicker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::kick_idle_peers, this));
+ m_standby_checker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::check_standby_peers, this));
return m_core.on_idle();
}
//------------------------------------------------------------------------------------------------------------------------
@@ -1245,6 +1246,22 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
+ bool t_cryptonote_protocol_handler<t_core>::check_standby_peers()
+ {
+ m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
+ {
+ if (context.m_state == cryptonote_connection_context::state_standby)
+ {
+ LOG_PRINT_CCONTEXT_L2("requesting callback");
+ ++context.m_callback_request_count;
+ m_p2p->request_callback(context);
+ }
+ return true;
+ });
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------
+ template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
@@ -1338,14 +1355,13 @@ skip:
bool start_from_current_chain = false;
if (!force_next_span)
{
- bool first = true;
- while (1)
+ do
{
size_t nblocks = m_block_queue.get_num_filled_spans();
size_t size = m_block_queue.get_data_size();
if (nblocks < BLOCK_QUEUE_NBLOCKS_THRESHOLD || size < BLOCK_QUEUE_SIZE_THRESHOLD)
{
- if (!first)
+ if (context.m_state != cryptonote_connection_context::state_standby)
{
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", resuming");
}
@@ -1368,10 +1384,9 @@ skip:
break;
}
- if (first)
+ if (context.m_state != cryptonote_connection_context::state_standby)
{
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", pausing");
- first = false;
context.m_state = cryptonote_connection_context::state_standby;
}
@@ -1385,13 +1400,8 @@ skip:
return true;
}
- for (size_t n = 0; n < 50; ++n)
- {
- if (m_stopping)
- return true;
- boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
- }
- }
+ return true;
+ } while(0);
context.m_state = cryptonote_connection_context::state_synchronizing;
}
@@ -1710,13 +1720,13 @@ skip:
{
std::string fluffyBlob;
epee::serialization::store_t_to_binary(fluffy_arg, fluffyBlob);
- m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, fluffyBlob, fluffyConnections);
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_FLUFFY_BLOCK::ID, epee::strspan<uint8_t>(fluffyBlob), fluffyConnections);
}
if (!fullConnections.empty())
{
std::string fullBlob;
epee::serialization::store_t_to_binary(arg, fullBlob);
- m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, fullBlob, fullConnections);
+ m_p2p->relay_notify_to_list(NOTIFY_NEW_BLOCK::ID, epee::strspan<uint8_t>(fullBlob), fullConnections);
}
return true;
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 853cde9c3..b5b747e97 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -163,9 +163,21 @@ bool t_command_parser_executor::print_height(const std::vector<std::string>& arg
bool t_command_parser_executor::print_block(const std::vector<std::string>& args)
{
+ bool include_hex = false;
+
+ // Assumes that optional flags come after mandatory argument <transaction_hash>
+ for (unsigned int i = 1; i < args.size(); ++i) {
+ if (args[i] == "+hex")
+ include_hex = true;
+ else
+ {
+ std::cout << "unexpected argument: " << args[i] << std::endl;
+ return true;
+ }
+ }
if (args.empty())
{
- std::cout << "expected: print_block (<block_hash> | <block_height>)" << std::endl;
+ std::cout << "expected: print_block (<block_hash> | <block_height>) [+hex]" << std::endl;
return false;
}
@@ -173,14 +185,14 @@ bool t_command_parser_executor::print_block(const std::vector<std::string>& args
try
{
uint64_t height = boost::lexical_cast<uint64_t>(arg);
- return m_executor.print_block_by_height(height);
+ return m_executor.print_block_by_height(height, include_hex);
}
catch (const boost::bad_lexical_cast&)
{
crypto::hash block_hash;
if (parse_hash256(arg, block_hash))
{
- return m_executor.print_block_by_hash(block_hash);
+ return m_executor.print_block_by_hash(block_hash, include_hex);
}
}
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 015e1e1f9..4c7d68686 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -66,7 +66,7 @@ namespace {
void print_block_header(cryptonote::block_header_response const & header)
{
tools::success_msg_writer()
- << "timestamp: " << boost::lexical_cast<std::string>(header.timestamp) << std::endl
+ << "timestamp: " << boost::lexical_cast<std::string>(header.timestamp) << " (" << tools::get_human_readable_timestamp(header.timestamp) << ")" << std::endl
<< "previous hash: " << header.prev_hash << std::endl
<< "nonce: " << boost::lexical_cast<std::string>(header.nonce) << std::endl
<< "is orphan: " << header.orphan_status << std::endl
@@ -569,7 +569,7 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u
if (!first)
tools::msg_writer() << "" << std::endl;
tools::msg_writer()
- << "height: " << header.height << ", timestamp: " << header.timestamp
+ << "height: " << header.height << ", timestamp: " << header.timestamp << " (" << tools::get_human_readable_timestamp(header.timestamp) << ")"
<< ", size: " << header.block_size << ", weight: " << header.block_weight << ", transactions: " << header.num_txes << std::endl
<< "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl
<< "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl
@@ -663,7 +663,7 @@ bool t_rpc_command_executor::print_height() {
return true;
}
-bool t_rpc_command_executor::print_block_by_hash(crypto::hash block_hash) {
+bool t_rpc_command_executor::print_block_by_hash(crypto::hash block_hash, bool include_hex) {
cryptonote::COMMAND_RPC_GET_BLOCK::request req;
cryptonote::COMMAND_RPC_GET_BLOCK::response res;
epee::json_rpc::error error_resp;
@@ -689,13 +689,15 @@ bool t_rpc_command_executor::print_block_by_hash(crypto::hash block_hash) {
}
}
+ if (include_hex)
+ tools::success_msg_writer() << res.blob << std::endl;
print_block_header(res.block_header);
tools::success_msg_writer() << res.json << ENDL;
return true;
}
-bool t_rpc_command_executor::print_block_by_height(uint64_t height) {
+bool t_rpc_command_executor::print_block_by_height(uint64_t height, bool include_hex) {
cryptonote::COMMAND_RPC_GET_BLOCK::request req;
cryptonote::COMMAND_RPC_GET_BLOCK::response res;
epee::json_rpc::error error_resp;
@@ -721,6 +723,8 @@ bool t_rpc_command_executor::print_block_by_height(uint64_t height) {
}
}
+ if (include_hex)
+ tools::success_msg_writer() << res.blob << std::endl;
print_block_header(res.block_header);
tools::success_msg_writer() << res.json << ENDL;
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index 592584a5f..1541a1a8e 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -91,9 +91,9 @@ public:
bool print_height();
- bool print_block_by_hash(crypto::hash block_hash);
+ bool print_block_by_hash(crypto::hash block_hash, bool include_hex);
- bool print_block_by_height(uint64_t height);
+ bool print_block_by_height(uint64_t height, bool include_hex);
bool print_transaction(crypto::hash transaction_hash, bool include_hex, bool include_json);
diff --git a/src/device_trezor/trezor/protocol.cpp b/src/device_trezor/trezor/protocol.cpp
index c4a92426c..13506a67f 100644
--- a/src/device_trezor/trezor/protocol.cpp
+++ b/src/device_trezor/trezor/protocol.cpp
@@ -877,6 +877,9 @@ namespace tx {
valueS.SetString(m_ct.enc_salt2.c_str(), m_ct.enc_salt2.size());
json.AddMember("salt2", valueS, json.GetAllocator());
+ valueS.SetString(m_ct.tx_prefix_hash.c_str(), m_ct.tx_prefix_hash.size());
+ json.AddMember("tx_prefix_hash", valueS, json.GetAllocator());
+
valueS.SetString(m_ct.enc_keys.c_str(), m_ct.enc_keys.size());
json.AddMember("enc_keys", valueS, json.GetAllocator());
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 8930418bd..0ef2dbb30 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -180,10 +180,10 @@ namespace nodetool
virtual void on_connection_close(p2p_connection_context& context);
virtual void callback(p2p_connection_context& context);
//----------------- i_p2p_endpoint -------------------------------------------------------------
- virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid> &connections);
- virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context);
- virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
- virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid> &connections);
+ virtual bool relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context);
+ virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context);
virtual bool drop_connection(const epee::net_utils::connection_context_base& context);
virtual void request_callback(const epee::net_utils::connection_context_base& context);
virtual void for_each_connection(std::function<bool(typename t_payload_net_handler::connection_context&, peerid_type, uint32_t)> f);
@@ -197,12 +197,12 @@ namespace nodetool
const boost::program_options::variables_map& vm
);
bool idle_worker();
- bool handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context);
+ bool handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context);
bool get_local_node_data(basic_node_data& node_data);
//bool get_local_handshake_data(handshake_data& hshd);
- bool merge_peerlist_with_local(const std::list<peerlist_entry>& bs);
- bool fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
+ bool merge_peerlist_with_local(const std::vector<peerlist_entry>& bs);
+ bool fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
bool connections_maker();
bool peer_sync_idle_maker();
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index fbf265fc9..25ac1ba18 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -33,6 +33,7 @@
#include <algorithm>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include <boost/bind.hpp>
#include <atomic>
@@ -740,7 +741,7 @@ namespace nodetool
if(rsp.node_data.network_id != m_network_id)
{
- LOG_WARNING_CC(context, "COMMAND_HANDSHAKE Failed, wrong network! (" << epee::string_tools::get_str_from_guid_a(rsp.node_data.network_id) << "), closing connection.");
+ LOG_WARNING_CC(context, "COMMAND_HANDSHAKE Failed, wrong network! (" << rsp.node_data.network_id << "), closing connection.");
return;
}
@@ -1374,7 +1375,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
+ bool node_server<t_payload_net_handler>::fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
{
//fix time delta
time_t now = 0;
@@ -1394,10 +1395,10 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
{
int64_t delta = 0;
- std::list<peerlist_entry> peerlist_ = peerlist;
+ std::vector<peerlist_entry> peerlist_ = peerlist;
if(!fix_time_delta(peerlist_, local_time, delta))
return false;
LOG_DEBUG_CC(context, "REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size());
@@ -1516,7 +1517,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid> &connections)
+ bool node_server<t_payload_net_handler>::relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid> &connections)
{
for(const auto& c_id: connections)
{
@@ -1526,7 +1527,7 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context)
{
std::list<boost::uuids::uuid> connections;
m_net_server.get_config_object().foreach_connection([&](const p2p_connection_context& cntxt)
@@ -1545,14 +1546,14 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)
{
int res = m_net_server.get_config_object().notify(command, req_buff, context.m_connection_id);
return res > 0;
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
+ bool node_server<t_payload_net_handler>::invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
{
int res = m_net_server.get_config_object().invoke(command, req_buff, resp_buff, context.m_connection_id);
return res > 0;
@@ -1686,7 +1687,7 @@ namespace nodetool
if(arg.node_data.network_id != m_network_id)
{
- LOG_INFO_CC(context, "WRONG NETWORK AGENT CONNECTED! id=" << epee::string_tools::get_str_from_guid_a(arg.node_data.network_id));
+ LOG_INFO_CC(context, "WRONG NETWORK AGENT CONNECTED! id=" << arg.node_data.network_id);
drop_connection(context);
add_host_fail(context.m_remote_address);
return 1;
@@ -1779,8 +1780,8 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::log_peerlist()
{
- std::list<peerlist_entry> pl_white;
- std::list<peerlist_entry> pl_gray;
+ std::vector<peerlist_entry> pl_white;
+ std::vector<peerlist_entry> pl_gray;
m_peerlist.get_peerlist_full(pl_gray, pl_white);
MINFO(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_white) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) );
return true;
@@ -1802,7 +1803,7 @@ namespace nodetool
{
ss << cntxt.m_remote_address.str()
<< " \t\tpeer_id " << cntxt.peer_id
- << " \t\tconn_id " << epee::string_tools::get_str_from_guid_a(cntxt.m_connection_id) << (cntxt.m_is_income ? " INC":" OUT")
+ << " \t\tconn_id " << cntxt.m_connection_id << (cntxt.m_is_income ? " INC":" OUT")
<< std::endl;
return true;
});
@@ -2016,7 +2017,7 @@ namespace nodetool
return false;
if (!m_peerlist.get_random_gray_peer(pe)) {
- return false;
+ return true;
}
bool success = check_connection_and_handshake_with_peer(pe.adr, pe.last_seen);
diff --git a/src/p2p/net_node_common.h b/src/p2p/net_node_common.h
index 218250efa..656c6155b 100644
--- a/src/p2p/net_node_common.h
+++ b/src/p2p/net_node_common.h
@@ -43,10 +43,10 @@ namespace nodetool
template<class t_connection_context>
struct i_p2p_endpoint
{
- virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid>& connections)=0;
- virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)=0;
- virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
- virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid>& connections)=0;
+ virtual bool relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)=0;
+ virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)=0;
virtual bool drop_connection(const epee::net_utils::connection_context_base& context)=0;
virtual void request_callback(const epee::net_utils::connection_context_base& context)=0;
virtual uint64_t get_connections_count()=0;
@@ -61,19 +61,19 @@ namespace nodetool
template<class t_connection_context>
struct p2p_endpoint_stub: public i_p2p_endpoint<t_connection_context>
{
- virtual bool relay_notify_to_list(int command, const std::string& data_buff, const std::list<boost::uuids::uuid>& connections)
+ virtual bool relay_notify_to_list(int command, const epee::span<const uint8_t> data_buff, const std::list<boost::uuids::uuid>& connections)
{
return false;
}
- virtual bool relay_notify_to_all(int command, const std::string& data_buff, const epee::net_utils::connection_context_base& context)
+ virtual bool relay_notify_to_all(int command, const epee::span<const uint8_t> data_buff, const epee::net_utils::connection_context_base& context)
{
return false;
}
- virtual bool invoke_command_to_peer(int command, const std::string& req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
+ virtual bool invoke_command_to_peer(int command, const epee::span<const uint8_t> req_buff, std::string& resp_buff, const epee::net_utils::connection_context_base& context)
{
return false;
}
- virtual bool invoke_notify_to_peer(int command, const std::string& req_buff, const epee::net_utils::connection_context_base& context)
+ virtual bool invoke_notify_to_peer(int command, const epee::span<const uint8_t> req_buff, const epee::net_utils::connection_context_base& context)
{
return true;
}
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index 1d609a37e..e7aad5abe 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -68,9 +68,9 @@ namespace nodetool
bool deinit();
size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();}
size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();}
- bool merge_peerlist(const std::list<peerlist_entry>& outer_bs);
- bool get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
- bool get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white);
+ bool merge_peerlist(const std::vector<peerlist_entry>& outer_bs);
+ bool get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
+ bool get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white);
bool get_white_peer_by_index(peerlist_entry& p, size_t i);
bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
bool append_with_peer_white(const peerlist_entry& pr);
@@ -265,7 +265,7 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::merge_peerlist(const std::list<peerlist_entry>& outer_bs)
+ bool peerlist_manager::merge_peerlist(const std::vector<peerlist_entry>& outer_bs)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
for(const peerlist_entry& be: outer_bs)
@@ -315,12 +315,13 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth)
+ bool peerlist_manager::get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>();
uint32_t cnt = 0;
+ bs_head.reserve(depth);
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index))
{
if(!vl.last_seen)
@@ -335,16 +336,18 @@ namespace nodetool
}
//--------------------------------------------------------------------------------------------------
inline
- bool peerlist_manager::get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white)
+ bool peerlist_manager::get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white)
{
CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index_gr=m_peers_gray.get<by_time>();
+ pl_gray.resize(pl_gray.size() + by_time_index_gr.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_gr))
{
pl_gray.push_back(vl);
}
peers_indexed::index<by_time>::type& by_time_index_wt=m_peers_white.get<by_time>();
+ pl_white.resize(pl_white.size() + by_time_index_wt.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_wt))
{
pl_white.push_back(vl);
diff --git a/src/p2p/p2p_protocol_defs.h b/src/p2p/p2p_protocol_defs.h
index e793e19b6..bb9d2635c 100644
--- a/src/p2p/p2p_protocol_defs.h
+++ b/src/p2p/p2p_protocol_defs.h
@@ -114,7 +114,7 @@ namespace nodetool
#pragma pack(pop)
inline
- std::string print_peerlist_to_string(const std::list<peerlist_entry>& pl)
+ std::string print_peerlist_to_string(const std::vector<peerlist_entry>& pl)
{
time_t now_time = 0;
time(&now_time);
@@ -189,7 +189,7 @@ namespace nodetool
{
basic_node_data node_data;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist_new;
+ std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(node_data)
@@ -198,7 +198,7 @@ namespace nodetool
{
// saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new)
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new)
{
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -217,7 +217,7 @@ namespace nodetool
// loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@@ -248,7 +248,7 @@ namespace nodetool
{
uint64_t local_time;
t_playload_type payload_data;
- std::list<peerlist_entry> local_peerlist_new;
+ std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(local_time)
@@ -257,7 +257,7 @@ namespace nodetool
{
// saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new)
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new)
{
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -276,7 +276,7 @@ namespace nodetool
// loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{
- std::list<peerlist_entry_base<network_address_old>> local_peerlist;
+ std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@@ -389,9 +389,9 @@ namespace nodetool
struct response
{
- std::list<peerlist_entry> local_peerlist_white;
- std::list<peerlist_entry> local_peerlist_gray;
- std::list<connection_entry> connections_list;
+ std::vector<peerlist_entry> local_peerlist_white;
+ std::vector<peerlist_entry> local_peerlist_gray;
+ std::vector<connection_entry> connections_list;
peerid_type my_id;
uint64_t local_time;
BEGIN_KV_SERIALIZE_MAP()
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index baa649f82..316f0e5e8 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -605,10 +605,19 @@ namespace rct {
keyV tmp(rows + 1);
size_t i;
keyM M(cols, tmp);
+ ge_p3 Cp3;
+ CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&Cp3, C.bytes) == 0, false, "point conv failed");
+ ge_cached Ccached;
+ ge_p3_to_cached(&Ccached, &Cp3);
+ ge_p1p1 p1;
//create the matrix to mg sig
for (i = 0; i < cols; i++) {
M[i][0] = pubs[i].dest;
- subKeys(M[i][1], pubs[i].mask, C);
+ ge_p3 p3;
+ CHECK_AND_ASSERT_MES_L1(ge_frombytes_vartime(&p3, pubs[i].mask.bytes) == 0, false, "point conv failed");
+ ge_sub(&p1, &p3, &Ccached);
+ ge_p1p1_to_p3(&p3, &p1);
+ ge_p3_tobytes(M[i][1].bytes, &p3);
}
//DP(C);
return MLSAG_Ver(message, M, mg, rows);
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 3851af3c8..d20000a53 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -252,19 +252,11 @@ namespace cryptonote
pruned_size += bd.first.first.size();
unpruned_size += bd.first.first.size();
res.output_indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices());
- res.output_indices.back().indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::tx_output_indices());
- if (!req.no_miner_tx)
- {
- bool r = m_core.get_tx_outputs_gindexs(bd.first.second, res.output_indices.back().indices.back().indices);
- if (!r)
- {
- res.status = "Failed";
- return false;
- }
- }
ntxes += bd.second.size();
+ res.output_indices.back().indices.reserve(1 + bd.second.size());
+ if (req.no_miner_tx)
+ res.output_indices.back().indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::tx_output_indices());
res.blocks.back().txs.reserve(bd.second.size());
- res.output_indices.back().indices.reserve(bd.second.size());
for (std::vector<std::pair<crypto::hash, cryptonote::blobdata>>::iterator i = bd.second.begin(); i != bd.second.end(); ++i)
{
unpruned_size += i->second.size();
@@ -272,14 +264,25 @@ namespace cryptonote
i->second.clear();
i->second.shrink_to_fit();
pruned_size += res.blocks.back().txs.back().size();
+ }
- res.output_indices.back().indices.push_back(COMMAND_RPC_GET_BLOCKS_FAST::tx_output_indices());
- bool r = m_core.get_tx_outputs_gindexs(i->first, res.output_indices.back().indices.back().indices);
+ const size_t n_txes_to_lookup = bd.second.size() + (req.no_miner_tx ? 0 : 1);
+ if (n_txes_to_lookup > 0)
+ {
+ std::vector<std::vector<uint64_t>> indices;
+ bool r = m_core.get_tx_outputs_gindexs(req.no_miner_tx ? bd.second.front().first : bd.first.second, n_txes_to_lookup, indices);
if (!r)
{
res.status = "Failed";
return false;
}
+ if (indices.size() != n_txes_to_lookup || res.output_indices.back().indices.size() != (req.no_miner_tx ? 1 : 0))
+ {
+ res.status = "Failed";
+ return false;
+ }
+ for (size_t i = 0; i < indices.size(); ++i)
+ res.output_indices.back().indices.push_back({std::move(indices[i])});
}
}
@@ -703,31 +706,31 @@ namespace cryptonote
if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed)
{
res.status = "Failed";
- res.reason = "";
+ std::string reason = "";
if ((res.low_mixin = tvc.m_low_mixin))
- add_reason(res.reason, "bad ring size");
+ add_reason(reason, "bad ring size");
if ((res.double_spend = tvc.m_double_spend))
- add_reason(res.reason, "double spend");
+ add_reason(reason, "double spend");
if ((res.invalid_input = tvc.m_invalid_input))
- add_reason(res.reason, "invalid input");
+ add_reason(reason, "invalid input");
if ((res.invalid_output = tvc.m_invalid_output))
- add_reason(res.reason, "invalid output");
+ add_reason(reason, "invalid output");
if ((res.too_big = tvc.m_too_big))
- add_reason(res.reason, "too big");
+ add_reason(reason, "too big");
if ((res.overspend = tvc.m_overspend))
- add_reason(res.reason, "overspend");
+ add_reason(reason, "overspend");
if ((res.fee_too_low = tvc.m_fee_too_low))
- add_reason(res.reason, "fee too low");
+ add_reason(reason, "fee too low");
if ((res.not_rct = tvc.m_not_rct))
- add_reason(res.reason, "tx is not ringct");
- const std::string punctuation = res.reason.empty() ? "" : ": ";
+ add_reason(reason, "tx is not ringct");
+ const std::string punctuation = reason.empty() ? "" : ": ";
if (tvc.m_verifivation_failed)
{
- LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << res.reason);
+ LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << reason);
}
else
{
- LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << res.reason);
+ LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << reason);
}
return true;
}
@@ -857,11 +860,11 @@ namespace cryptonote
bool core_rpc_server::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res)
{
PERF_TIMER(on_get_peer_list);
- std::list<nodetool::peerlist_entry> white_list;
- std::list<nodetool::peerlist_entry> gray_list;
+ std::vector<nodetool::peerlist_entry> white_list;
+ std::vector<nodetool::peerlist_entry> gray_list;
m_p2p.get_peerlist_manager().get_peerlist_full(gray_list, white_list);
-
+ res.white_list.reserve(white_list.size());
for (auto & entry : white_list)
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@@ -871,6 +874,7 @@ namespace cryptonote
res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen);
}
+ res.gray_list.reserve(gray_list.size());
for (auto & entry : gray_list)
{
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 2556a3607..835abf569 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -136,6 +136,7 @@ namespace
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
const command_line::arg_descriptor<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
+ const command_line::arg_descriptor<std::string> arg_restore_date = {"restore-date", sw::tr("Restore from estimated blockchain height on specified date"), ""};
const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
const command_line::arg_descriptor<bool> arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false};
const command_line::arg_descriptor<std::string> arg_subaddress_lookahead = {"subaddress-lookahead", tools::wallet2::tr("Set subaddress lookahead sizes to <major>:<minor>"), ""};
@@ -146,7 +147,7 @@ namespace
const char* USAGE_START_MINING("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]");
const char* USAGE_SET_DAEMON("set_daemon <host>[:<port>] [trusted|untrusted]");
const char* USAGE_SHOW_BALANCE("balance [detail]");
- const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [index=<N1>[,<N2>[,...]]]");
+ const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]");
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
const char* USAGE_PAYMENT_ID("payment_id");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]");
@@ -540,7 +541,7 @@ namespace
}
catch (const tools::error::tx_rejected& e)
{
- fail_msg_writer() << (boost::format(sw::tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
+ fail_msg_writer() << (boost::format(sw::tr("transaction %s was rejected by daemon")) % get_transaction_hash(e.tx()));
std::string reason = e.reason();
if (!reason.empty())
fail_msg_writer() << sw::tr("Reason: ") << reason;
@@ -2488,6 +2489,19 @@ bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string>
return true;
}
+bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ parse_bool_and_use(args[1], [&](bool r) {
+ m_wallet->track_uses(r);
+ m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ });
+ }
+ return true;
+}
+
bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -3032,6 +3046,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second;
success_msg_writer() << "segregation-height = " << m_wallet->segregation_height();
success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs();
+ success_msg_writer() << "track-uses = " << m_wallet->track_uses();
success_msg_writer() << "device_name = " << m_wallet->device_name();
return true;
}
@@ -3088,6 +3103,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>"));
CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
@@ -3245,6 +3261,28 @@ static bool might_be_partial_seed(const epee::wipeable_string &words)
return seed.size() < 24;
}
//----------------------------------------------------------------------------------------------------
+static bool datestr_to_int(const std::string &heightstr, uint16_t &year, uint8_t &month, uint8_t &day)
+{
+ if (heightstr.size() != 10 || heightstr[4] != '-' || heightstr[7] != '-')
+ {
+ fail_msg_writer() << tr("date format must be YYYY-MM-DD");
+ return false;
+ }
+ try
+ {
+ year = boost::lexical_cast<uint16_t>(heightstr.substr(0,4));
+ // lexical_cast<uint8_t> won't work because uint8_t is treated as character type
+ month = boost::lexical_cast<uint16_t>(heightstr.substr(5,2));
+ day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2));
+ }
+ catch (const boost::bad_lexical_cast &)
+ {
+ fail_msg_writer() << tr("bad height parameter: ") << heightstr;
+ return false;
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){
@@ -3685,7 +3723,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
tools::scoped_message_writer wrt = tools::msg_writer();
wrt << tr("No restore height is specified.");
wrt << tr("Assumed you are creating a new account, restore will be done from current estimated blockchain height.");
- wrt << tr("Use --restore-height if you want to restore an already setup account from a specific height");
+ wrt << tr("Use --restore-height or --restore-date if you want to restore an already setup account from a specific height");
}
std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
if (std::cin.eof() || !command_line::is_yes(confirm))
@@ -3714,7 +3752,26 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (m_restoring && m_generate_from_json.empty() && m_generate_from_device.empty())
{
- m_wallet->explicit_refresh_from_block_height(!command_line::is_arg_defaulted(vm, arg_restore_height));
+ m_wallet->explicit_refresh_from_block_height(!(command_line::is_arg_defaulted(vm, arg_restore_height) ||
+ command_line::is_arg_defaulted(vm, arg_restore_date)));
+ if (command_line::is_arg_defaulted(vm, arg_restore_height) && !command_line::is_arg_defaulted(vm, arg_restore_date))
+ {
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+ if (!datestr_to_int(m_restore_date, year, month, day))
+ return false;
+ try
+ {
+ m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
+ success_msg_writer() << tr("Restore height is: ") << m_restore_height;
+ }
+ catch (const std::runtime_error& e)
+ {
+ fail_msg_writer() << e.what();
+ return false;
+ }
+ }
}
if (!m_wallet->explicit_refresh_from_block_height() && m_restoring)
{
@@ -3746,20 +3803,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("bad m_restore_height parameter: ") << heightstr;
continue;
}
- if (heightstr.size() != 10 || heightstr[4] != '-' || heightstr[7] != '-')
- {
- fail_msg_writer() << tr("date format must be YYYY-MM-DD");
- continue;
- }
uint16_t year;
uint8_t month; // 1, 2, ..., 12
uint8_t day; // 1, 2, ..., 31
try
{
- year = boost::lexical_cast<uint16_t>(heightstr.substr(0,4));
- // lexical_cast<uint8_t> won't work because uint8_t is treated as character type
- month = boost::lexical_cast<uint16_t>(heightstr.substr(5,2));
- day = boost::lexical_cast<uint16_t>(heightstr.substr(8,2));
+ if (!datestr_to_int(heightstr, year, month, day))
+ return false;
m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
success_msg_writer() << tr("Restore height is: ") << m_restore_height;
std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
@@ -3846,6 +3896,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
m_restore_height = command_line::get_arg(vm, arg_restore_height);
+ m_restore_date = command_line::get_arg(vm, arg_restore_date);
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
m_subaddress_lookahead = command_line::get_arg(vm, arg_subaddress_lookahead);
m_use_english_language_names = command_line::get_arg(vm, arg_use_english_language_names);
@@ -3858,6 +3909,14 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_restore_deterministic_wallet ||
m_restore_multisig_wallet;
+ if (!command_line::is_arg_defaulted(vm, arg_restore_date))
+ {
+ uint16_t year;
+ uint8_t month, day;
+ if (!datestr_to_int(m_restore_date, year, month, day))
+ return false;
+ }
+
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -4813,6 +4872,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
bool filter = false;
bool available = false;
bool verbose = false;
+ bool uses = false;
if (local_args.size() > 0)
{
if (local_args[0] == "available")
@@ -4828,12 +4888,22 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
local_args.erase(local_args.begin());
}
}
- if (local_args.size() > 0 && local_args[0] == "verbose")
+ while (local_args.size() > 0)
{
- verbose = true;
+ if (local_args[0] == "verbose")
+ verbose = true;
+ else if (local_args[0] == "uses")
+ uses = true;
+ else
+ {
+ fail_msg_writer() << tr("Invalid keyword: ") << local_args.front();
+ break;
+ }
local_args.erase(local_args.begin());
}
+ const uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
+
PAUSE_READLINE();
std::set<uint32_t> subaddr_indices;
@@ -4867,9 +4937,16 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
verbose_string = (boost::format("%68s%68s") % tr("pubkey") % tr("key image")).str();
message_writer() << boost::format("%21s%8s%12s%8s%16s%68s%16s%s") % tr("amount") % tr("spent") % tr("unlocked") % tr("ringct") % tr("global index") % tr("tx id") % tr("addr index") % verbose_string;
}
- std::string verbose_string;
+ std::string extra_string;
if (verbose)
- verbose_string = (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str();
+ extra_string += (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str();
+ if (uses)
+ {
+ std::vector<uint64_t> heights;
+ for (const auto &e: td.m_uses) heights.push_back(e.first);
+ const std::pair<std::string, std::string> line = show_outputs_line(heights, blockchain_height, td.m_spent_height);
+ extra_string += tr("Heights: ") + line.first + "\n" + line.second;
+ }
message_writer(td.m_spent ? console_color_magenta : console_color_green, false) <<
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
print_money(td.amount()) %
@@ -4879,7 +4956,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
td.m_global_output_index %
td.m_txid %
td.m_subaddr_index.minor %
- verbose_string;
+ extra_string;
++transfers_found;
}
}
@@ -5031,6 +5108,33 @@ bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
+std::pair<std::string, std::string> simple_wallet::show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height) const
+{
+ std::stringstream ostr;
+
+ for (uint64_t h: heights)
+ blockchain_height = std::max(blockchain_height, h);
+
+ for (size_t j = 0; j < heights.size(); ++j)
+ ostr << (heights[j] == highlight_height ? " *" : " ") << heights[j];
+
+ // visualize the distribution, using the code by moneroexamples onion-monero-viewer
+ const uint64_t resolution = 79;
+ std::string ring_str(resolution, '_');
+ for (size_t j = 0; j < heights.size(); ++j)
+ {
+ uint64_t pos = (heights[j] * resolution) / blockchain_height;
+ ring_str[pos] = 'o';
+ }
+ if (highlight_height < blockchain_height)
+ {
+ uint64_t pos = (highlight_height * resolution) / blockchain_height;
+ ring_str[pos] = '*';
+ }
+
+ return std::make_pair(ostr.str(), ring_str);
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr)
{
uint32_t version;
@@ -5101,21 +5205,18 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
}
}
ostr << tr("\nOriginating block heights: ");
- for (size_t j = 0; j < absolute_offsets.size(); ++j)
- ostr << tr(j == source.real_output ? " *" : " ") << res.outs[j].height;
spent_key_height[i] = res.outs[source.real_output].height;
spent_key_txid [i] = res.outs[source.real_output].txid;
- // visualize the distribution, using the code by moneroexamples onion-monero-viewer
- const uint64_t resolution = 79;
- std::string ring_str(resolution, '_');
+ std::vector<uint64_t> heights(absolute_offsets.size(), 0);
+ uint64_t highlight_height = std::numeric_limits<uint64_t>::max();
for (size_t j = 0; j < absolute_offsets.size(); ++j)
{
- uint64_t pos = (res.outs[j].height * resolution) / blockchain_height;
- ring_str[pos] = 'o';
+ heights[j] = res.outs[j].height;
+ if (j == source.real_output)
+ highlight_height = heights[j];
}
- uint64_t pos = (res.outs[source.real_output].height * resolution) / blockchain_height;
- ring_str[pos] = '*';
- ostr << tr("\n|") << ring_str << tr("|\n");
+ std::pair<std::string, std::string> ring_str = show_outputs_line(heights, highlight_height);
+ ostr << ring_str.first << tr("\n|") << ring_str.second << tr("|\n");
}
// warn if rings contain keys originating from the same tx or temporally very close block heights
bool are_keys_from_same_tx = false;
@@ -5218,19 +5319,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
payment_id_seen = true;
message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead");
}
- else
- {
- crypto::hash8 payment_id8;
- if (tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8))
- {
- std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- local_args.pop_back();
- payment_id_seen = true;
- }
- }
-
if(!r)
{
fail_msg_writer() << tr("payment id failed to encode");
@@ -5883,18 +5971,6 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
payment_id_seen = true;
}
- else
- {
- crypto::hash8 payment_id8;
- r = tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8);
- if(r)
- {
- std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
- r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
- payment_id_seen = true;
- }
- }
if(!r && local_args.size() == 3)
{
@@ -6147,10 +6223,6 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
{
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
}
- else if(tools::wallet2::parse_short_payment_id(local_args.back(), payment_id8))
- {
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
- }
else
{
fail_msg_writer() << tr("failed to parse Payment ID");
@@ -7239,6 +7311,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
const std::string type = pd.m_coinbase ? tr("block") : tr("in");
const bool unlocked = m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height);
transfers.push_back({
+ type,
pd.m_block_height,
pd.m_timestamp,
type,
@@ -7271,6 +7344,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
payment_id = payment_id.substr(0,16);
std::string note = m_wallet->get_tx_note(i->first);
transfers.push_back({
+ "out",
pd.m_block_height,
pd.m_timestamp,
"out",
@@ -7308,6 +7382,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
double_spend_note = tr("[Double spend seen on the network: this transaction may or may not end up being mined] ");
transfers.push_back({
"pool",
+ "pool",
pd.m_timestamp,
"in",
false,
@@ -7348,6 +7423,7 @@ bool simple_wallet::get_transfers(std::vector<std::string>& local_args, std::vec
if ((failed && is_failed) || (!is_failed && pending)) {
transfers.push_back({
(is_failed ? "failed" : "pending"),
+ (is_failed ? "failed" : "pending"),
pd.m_timestamp,
"out",
false,
@@ -7395,7 +7471,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
for (const auto& transfer : all_transfers)
{
- const auto color = transfer.confirmed ? ((transfer.direction == "in" || transfer.direction == "block") ? console_color_green : console_color_magenta) : console_color_white;
+ const auto color = transfer.type == "failed" ? console_color_red : transfer.confirmed ? ((transfer.direction == "in" || transfer.direction == "block") ? console_color_green : console_color_magenta) : console_color_default;
std::string destinations = "-";
if (!transfer.outputs.empty())
@@ -8150,8 +8226,8 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
}
else if (tools::wallet2::parse_short_payment_id(args[3], info.payment_id))
{
- memcpy(payment_id.data, info.payment_id.data, 8);
- description_start += 2;
+ fail_msg_writer() << tr("Short payment IDs are to be used within an integrated address only");
+ return true;
}
else
{
@@ -8867,6 +8943,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_electrum_seed );
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
command_line::add_arg(desc_params, arg_restore_height);
+ command_line::add_arg(desc_params, arg_restore_date);
command_line::add_arg(desc_params, arg_do_not_relay);
command_line::add_arg(desc_params, arg_create_address_file);
command_line::add_arg(desc_params, arg_subaddress_lookahead);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 5010e3adc..f364df2ff 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -142,6 +142,7 @@ namespace cryptonote
bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>());
bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>());
bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
@@ -251,9 +252,11 @@ namespace cryptonote
bool print_seed(bool encrypted);
void key_images_sync_intern();
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
+ std::pair<std::string, std::string> show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height = std::numeric_limits<uint64_t>::max()) const;
struct transfer_view
{
+ std::string type;
boost::variant<uint64_t, std::string> block;
uint64_t timestamp;
std::string direction;
@@ -367,6 +370,7 @@ namespace cryptonote
std::string m_mnemonic_language;
std::string m_import_path;
std::string m_subaddress_lookahead;
+ std::string m_restore_date; // optional - converted to m_restore_height
epee::wipeable_string m_electrum_seed; // electrum-style seed parameter
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 7cd3b65bb..595dbac5e 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -942,6 +942,12 @@ uint64_t WalletImpl::approximateBlockChainHeight() const
{
return m_wallet->get_approximate_blockchain_height();
}
+
+uint64_t WalletImpl::estimateBlockChainHeight() const
+{
+ return m_wallet->estimate_blockchain_height();
+}
+
uint64_t WalletImpl::daemonBlockChainHeight() const
{
if(m_wallet->light_wallet()) {
@@ -1149,7 +1155,7 @@ std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addre
}
catch (const std::exception &e)
{
- LOG_ERROR("Error getting subaddress label: ") << e.what();
+ LOG_ERROR("Error getting subaddress label: " << e.what());
setStatusError(string(tr("Failed to get subaddress label: ")) + e.what());
return "";
}
@@ -1162,7 +1168,7 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex
}
catch (const std::exception &e)
{
- LOG_ERROR("Error setting subaddress label: ") << e.what();
+ LOG_ERROR("Error setting subaddress label: " << e.what());
setStatusError(string(tr("Failed to set subaddress label: ")) + e.what());
}
}
@@ -1179,7 +1185,7 @@ string WalletImpl::getMultisigInfo() const {
clearStatus();
return m_wallet->get_multisig_info();
} catch (const exception& e) {
- LOG_ERROR("Error on generating multisig info: ") << e.what();
+ LOG_ERROR("Error on generating multisig info: " << e.what());
setStatusError(string(tr("Failed to get multisig info: ")) + e.what());
}
@@ -1196,7 +1202,7 @@ string WalletImpl::makeMultisig(const vector<string>& info, uint32_t threshold)
return m_wallet->make_multisig(epee::wipeable_string(m_password), info, threshold);
} catch (const exception& e) {
- LOG_ERROR("Error on making multisig wallet: ") << e.what();
+ LOG_ERROR("Error on making multisig wallet: " << e.what());
setStatusError(string(tr("Failed to make multisig: ")) + e.what());
}
@@ -1210,7 +1216,7 @@ std::string WalletImpl::exchangeMultisigKeys(const std::vector<std::string> &inf
return m_wallet->exchange_multisig_keys(epee::wipeable_string(m_password), info);
} catch (const exception& e) {
- LOG_ERROR("Error on exchanging multisig keys: ") << e.what();
+ LOG_ERROR("Error on exchanging multisig keys: " << e.what());
setStatusError(string(tr("Failed to make multisig: ")) + e.what());
}
@@ -1228,7 +1234,7 @@ bool WalletImpl::finalizeMultisig(const vector<string>& extraMultisigInfo) {
setStatusError(tr("Failed to finalize multisig wallet creation"));
} catch (const exception& e) {
- LOG_ERROR("Error on finalizing multisig wallet creation: ") << e.what();
+ LOG_ERROR("Error on finalizing multisig wallet creation: " << e.what());
setStatusError(string(tr("Failed to finalize multisig wallet creation: ")) + e.what());
}
@@ -1244,7 +1250,7 @@ bool WalletImpl::exportMultisigImages(string& images) {
images = epee::string_tools::buff_to_hex_nodelimer(blob);
return true;
} catch (const exception& e) {
- LOG_ERROR("Error on exporting multisig images: ") << e.what();
+ LOG_ERROR("Error on exporting multisig images: " << e.what());
setStatusError(string(tr("Failed to export multisig images: ")) + e.what());
}
@@ -1272,7 +1278,7 @@ size_t WalletImpl::importMultisigImages(const vector<string>& images) {
return m_wallet->import_multisig(blobs);
} catch (const exception& e) {
- LOG_ERROR("Error on importing multisig images: ") << e.what();
+ LOG_ERROR("Error on importing multisig images: " << e.what());
setStatusError(string(tr("Failed to import multisig images: ")) + e.what());
}
@@ -1286,7 +1292,7 @@ bool WalletImpl::hasMultisigPartialKeyImages() const {
return m_wallet->has_multisig_partial_key_images();
} catch (const exception& e) {
- LOG_ERROR("Error on checking for partial multisig key images: ") << e.what();
+ LOG_ERROR("Error on checking for partial multisig key images: " << e.what());
setStatusError(string(tr("Failed to check for partial multisig key images: ")) + e.what());
}
@@ -1314,7 +1320,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
return ptx;
} catch (exception& e) {
- LOG_ERROR("Error on restoring multisig transaction: ") << e.what();
+ LOG_ERROR("Error on restoring multisig transaction: " << e.what());
setStatusError(string(tr("Failed to restore multisig transaction: ")) + e.what());
}
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index b4637b8e6..55240d64f 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -109,6 +109,7 @@ public:
uint64_t unlockedBalance(uint32_t accountIndex = 0) const override;
uint64_t blockChainHeight() const override;
uint64_t approximateBlockChainHeight() const override;
+ uint64_t estimateBlockChainHeight() const override;
uint64_t daemonBlockChainHeight() const override;
uint64_t daemonBlockChainTargetHeight() const override;
bool synchronized() const override;
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index 82627de29..5c301974f 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -575,6 +575,12 @@ struct Wallet
virtual uint64_t approximateBlockChainHeight() const = 0;
/**
+ * @brief estimateBlockChainHeight - returns estimate blockchain height. More accurate than approximateBlockChainHeight,
+ * uses daemon height and falls back to calculation from date/time
+ * @return
+ **/
+ virtual uint64_t estimateBlockChainHeight() const = 0;
+ /**
* @brief daemonBlockChainHeight - returns daemon blockchain height
* @return 0 - in case error communicating with the daemon.
* status() will return Status_Error and errorString() will return verbose error description
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index 5b262f1b7..89fe01c0d 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -127,6 +127,8 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds);
if(restoreHeight > 0){
wallet->setRefreshFromBlockHeight(restoreHeight);
+ } else {
+ wallet->setRefreshFromBlockHeight(wallet->estimateBlockChainHeight());
}
auto lookahead = tools::parse_subaddress_lookahead(subaddressLookahead);
if (lookahead)
diff --git a/src/wallet/message_store.cpp b/src/wallet/message_store.cpp
index ce6f4f52b..7381005c1 100644
--- a/src/wallet/message_store.cpp
+++ b/src/wallet/message_store.cpp
@@ -125,7 +125,7 @@ void message_store::set_signer(const multisig_wallet_state &state,
const boost::optional<std::string> &transport_address,
const boost::optional<cryptonote::account_public_address> monero_address)
{
- THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index);
+ THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
authorized_signer &m = m_signers[index];
if (label)
{
@@ -146,7 +146,7 @@ void message_store::set_signer(const multisig_wallet_state &state,
const authorized_signer &message_store::get_signer(uint32_t index) const
{
- THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index);
+ THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
return m_signers[index];
}
@@ -201,7 +201,7 @@ void message_store::unpack_signer_config(const multisig_wallet_state &state, con
THROW_WALLET_EXCEPTION_IF(true, tools::error::wallet_internal_error, "Invalid structure of signer config");
}
uint32_t num_signers = (uint32_t)signers.size();
- THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + num_signers);
+ THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + std::to_string(num_signers));
}
void message_store::process_signer_config(const multisig_wallet_state &state, const std::string &signer_config)
@@ -424,7 +424,7 @@ void message_store::setup_signer_for_auto_config(uint32_t index, const std::stri
// auto-config parameters. In the wallet of somebody using the token to send auto-config
// data the auto-config parameters are stored in the "me" signer and taken from there
// to send that data.
- THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index);
+ THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
authorized_signer &m = m_signers[index];
m.auto_config_token = token;
crypto::hash_to_scalar(token.data(), token.size(), m.auto_config_secret_key);
@@ -506,7 +506,7 @@ void message_store::process_wallet_created_data(const multisig_wallet_state &sta
break;
default:
- THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Illegal message type " + (uint32_t)type);
+ THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Illegal message type " + std::to_string((uint32_t)type));
break;
}
}
@@ -573,7 +573,7 @@ size_t message_store::get_message_index_by_id(uint32_t id) const
{
size_t index;
bool found = get_message_index_by_id(id, index);
- THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + id);
+ THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + std::to_string(id));
return index;
}
@@ -601,7 +601,7 @@ message message_store::get_message_by_id(uint32_t id) const
{
message m;
bool found = get_message_by_id(id, m);
- THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + id);
+ THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + std::to_string(id));
return m;
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 0d2faca54..8b2735b01 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -192,6 +192,37 @@ namespace
return false;
}
+
+ void add_reason(std::string &reasons, const char *reason)
+ {
+ if (!reasons.empty())
+ reasons += ", ";
+ reasons += reason;
+ }
+
+ std::string get_text_reason(const cryptonote::COMMAND_RPC_SEND_RAW_TX::response &res)
+ {
+ std::string reason;
+ if (res.low_mixin)
+ add_reason(reason, "bad ring size");
+ if (res.double_spend)
+ add_reason(reason, "double spend");
+ if (res.invalid_input)
+ add_reason(reason, "invalid input");
+ if (res.invalid_output)
+ add_reason(reason, "invalid output");
+ if (res.too_big)
+ add_reason(reason, "too big");
+ if (res.overspend)
+ add_reason(reason, "overspend");
+ if (res.fee_too_low)
+ add_reason(reason, "fee too low");
+ if (res.not_rct)
+ add_reason(reason, "tx is not ringct");
+ if (res.not_relayed)
+ add_reason(reason, "tx was not relayed");
+ return reason;
+ }
}
namespace
@@ -583,19 +614,6 @@ std::pair<std::unique_ptr<tools::wallet2>, tools::password_container> generate_f
return {nullptr, tools::password_container{}};
}
-static void throw_on_rpc_response_error(const boost::optional<std::string> &status, const char *method)
-{
- // no error
- if (!status)
- return;
-
- // empty string -> not connection
- THROW_WALLET_EXCEPTION_IF(status->empty(), tools::error::no_connection_to_daemon, method);
-
- THROW_WALLET_EXCEPTION_IF(*status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, method);
- THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, *status);
-}
-
std::string strjoin(const std::vector<size_t> &V, const char *sep)
{
std::stringstream ss;
@@ -894,6 +912,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_key_reuse_mitigation2(true),
m_segregation_height(0),
m_ignore_fractional_outputs(true),
+ m_track_uses(false),
m_is_initialized(false),
m_kdf_rounds(kdf_rounds),
is_old_file_format(false),
@@ -901,6 +920,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_multisig(false),
m_multisig_threshold(0),
m_node_rpc_proxy(m_http_client, 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),
m_light_wallet(false),
@@ -917,6 +937,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_last_block_reward(0),
m_encrypt_keys_after_refresh(boost::none),
m_unattended(unattended),
+ m_devices_registered(false),
m_device_last_key_image_sync(0)
{
}
@@ -1446,8 +1467,9 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
}
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data)
+void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, 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)
{
+ PERF_TIMER(process_new_transaction);
// In this function, tx (probably) only contains the base information
// (that is, the prunable stuff may or may not be included)
if (!miner_tx && !pool)
@@ -1684,6 +1706,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (!m_multisig && !m_watch_only)
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = m_transfers.size() - 1;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1749,6 +1773,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity();
td.m_rct = false;
}
+ if (output_tracker_cache)
+ (*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = kit->second;
if (m_multisig)
{
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@@ -1780,11 +1806,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
if(in.type() != typeid(cryptonote::txin_to_key))
continue;
- auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
+ const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(in);
+ auto it = m_key_images.find(in_to_key.k_image);
if(it != m_key_images.end())
{
transfer_details& td = m_transfers[it->second];
- uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
+ uint64_t amount = in_to_key.amount;
if (amount > 0)
{
if(amount != td.amount())
@@ -1815,6 +1842,34 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
}
}
+
+ if (!pool && m_track_uses)
+ {
+ PERF_TIMER(track_uses);
+ const uint64_t amount = in_to_key.amount;
+ std::vector<uint64_t> offsets = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
+ if (output_tracker_cache)
+ {
+ for (uint64_t offset: offsets)
+ {
+ const std::map<std::pair<uint64_t, uint64_t>, size_t>::const_iterator i = output_tracker_cache->find(std::make_pair(amount, offset));
+ if (i != output_tracker_cache->end())
+ {
+ size_t idx = i->second;
+ THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Output tracker cache index out of range");
+ m_transfers[idx].m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
+ }
+ else for (transfer_details &td: m_transfers)
+ {
+ if (amount != in_to_key.amount)
+ continue;
+ for (uint64_t offset: offsets)
+ if (offset == td.m_global_output_index)
+ td.m_uses.push_back(std::make_pair(height, txid));
+ }
+ }
}
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
@@ -1997,7 +2052,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
add_rings(tx);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::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)
+void wallet2::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)
{
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
"block transactions=" + std::to_string(bche.txs.size()) +
@@ -2010,7 +2065,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
{
TIME_MEASURE_START(miner_tx_handle_time);
if (m_refresh_type != RefreshNoCoinbase)
- process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset]);
+ process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
++tx_cache_data_offset;
TIME_MEASURE_FINISH(miner_tx_handle_time);
@@ -2019,7 +2074,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
{
- process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++]);
+ process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
}
TIME_MEASURE_FINISH(txs_handle_time);
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
@@ -2089,7 +2144,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblocks.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblocks.bin");
- THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, res.status);
+ THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, 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 (" +
boost::lexical_cast<std::string>(res.output_indices.size()) + ") sizes from daemon");
@@ -2111,13 +2166,13 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gethashes.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gethashes.bin");
- THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_hashes_error, res.status);
+ THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_hashes_error, get_rpc_status(res.status));
blocks_start_height = res.start_height;
hashes = std::move(res.m_block_ids);
}
//----------------------------------------------------------------------------------------------------
-void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added)
+void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{
size_t current_index = start_height;
blocks_added = 0;
@@ -2156,7 +2211,6 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
const cryptonote::account_keys &keys = m_account.get_keys();
auto gender = [&](wallet2::is_out_data &iod) {
- boost::unique_lock<hw::device> hwdev_lock(hwdev);
if (!hwdev.generate_key_derivation(iod.pkey, keys.m_view_secret_key, iod.derivation))
{
MWARNING("Failed to generate key derivation from tx pubkey, skipping");
@@ -2165,12 +2219,16 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
}
};
- for (auto &slot: tx_cache_data)
+ for (size_t i = 0; i < tx_cache_data.size(); ++i)
{
- for (auto &iod: slot.primary)
- tpool.submit(&waiter, [&gender, &iod]() { gender(iod); }, true);
- for (auto &iod: slot.additional)
- tpool.submit(&waiter, [&gender, &iod]() { gender(iod); }, true);
+ tpool.submit(&waiter, [&hwdev, &gender, &tx_cache_data, i]() {
+ auto &slot = tx_cache_data[i];
+ boost::unique_lock<hw::device> hwdev_lock(hwdev);
+ for (auto &iod: slot.primary)
+ gender(iod);
+ for (auto &iod: slot.additional)
+ gender(iod);
+ }, true);
}
waiter.wait(&tpool);
@@ -2224,7 +2282,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
if(current_index >= m_blockchain.size())
{
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
++blocks_added;
}
else if(bl_id != m_blockchain[current_index])
@@ -2236,7 +2294,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
string_tools::pod_to_hex(m_blockchain[current_index]));
detach_blockchain(current_index);
- process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset);
+ process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
}
else
{
@@ -2270,11 +2328,10 @@ void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks
THROW_WALLET_EXCEPTION_IF(prev_blocks.size() != prev_parsed_blocks.size(), error::wallet_internal_error, "size mismatch");
// prepend the last 3 blocks, should be enough to guard against a block or two's reorg
- std::vector<parsed_block>::const_reverse_iterator i = prev_parsed_blocks.rbegin();
- for (size_t n = 0; n < std::min((size_t)3, prev_parsed_blocks.size()); ++n)
+ auto s = std::next(prev_parsed_blocks.rbegin(), std::min((size_t)3, prev_parsed_blocks.size())).base();
+ for (; s != prev_parsed_blocks.end(); ++s)
{
- short_chain_history.push_front(i->hash);
- ++i;
+ short_chain_history.push_front(s->hash);
}
// pull the new blocks
@@ -2573,7 +2630,7 @@ void wallet2::update_pool_state(bool refreshed)
}
else
{
- LOG_PRINT_L0("Error calling gettransactions daemon RPC: r " << r << ", status " << res.status);
+ LOG_PRINT_L0("Error calling gettransactions daemon RPC: r " << r << ", status " << get_rpc_status(res.status));
}
}
MTRACE("update_pool_state end");
@@ -2669,6 +2726,17 @@ bool wallet2::delete_address_book_row(std::size_t row_id) {
}
//----------------------------------------------------------------------------------------------------
+std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create_output_tracker_cache() const
+{
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> cache{new std::map<std::pair<uint64_t, uint64_t>, size_t>()};
+ for (size_t i = 0; i < m_transfers.size(); ++i)
+ {
+ const transfer_details &td = m_transfers[i];
+ (*cache)[std::make_pair(td.is_rct() ? 0 : td.amount(), td.m_global_output_index)] = i;
+ }
+ return cache;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
{
if(m_light_wallet) {
@@ -2715,6 +2783,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
std::vector<cryptonote::block_complete_entry> blocks;
std::vector<parsed_block> parsed_blocks;
bool refreshed = false;
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> output_tracker_cache;
// pull the first set of blocks
get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
@@ -2749,13 +2818,16 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
bool first = true;
while(m_run.load(std::memory_order_relaxed))
{
+ uint64_t next_blocks_start_height;
+ std::vector<cryptonote::block_complete_entry> next_blocks;
+ std::vector<parsed_block> next_parsed_blocks;
+ bool error;
try
{
// pull the next set of blocks while we're processing the current one
- uint64_t next_blocks_start_height;
- std::vector<cryptonote::block_complete_entry> next_blocks;
- std::vector<parsed_block> next_parsed_blocks;
- bool error = false;
+ error = false;
+ next_blocks.clear();
+ next_parsed_blocks.clear();
added_blocks = 0;
if (!first && blocks.empty())
{
@@ -2768,7 +2840,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
{
try
{
- process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks);
+ process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks, output_tracker_cache.get());
}
catch (const tools::error::out_of_hashchain_bounds_error&)
{
@@ -2793,6 +2865,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
start_height = stop_height;
throw std::runtime_error(""); // loop again
}
+ catch (const std::exception &e)
+ {
+ MERROR("Error parsing blocks: " << e.what());
+ error = true;
+ }
blocks_fetched += added_blocks;
}
waiter.wait(&tpool);
@@ -2811,6 +2888,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
throw std::runtime_error("proxy exception in refresh thread");
}
+ // if we've got at least 10 blocks to refresh, assume we're starting
+ // a long refresh, and setup a tracking output cache if we need to
+ if (m_track_uses && !output_tracker_cache && next_blocks.size() >= 10)
+ output_tracker_cache = create_output_tracker_cache();
+
// switch to the new blocks from the daemon
blocks_start_height = next_blocks_start_height;
blocks = std::move(next_blocks);
@@ -3183,6 +3265,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
+ value2.SetInt(m_track_uses ? 1 : 0);
+ json.AddMember("track_uses", value2, json.GetAllocator());
+
value2.SetUint(m_subaddress_lookahead_major);
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
@@ -3329,6 +3414,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_key_reuse_mitigation2 = true;
m_segregation_height = 0;
m_ignore_fractional_outputs = true;
+ m_track_uses = false;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false;
@@ -3481,6 +3567,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = field_segregation_height;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
m_ignore_fractional_outputs = field_ignore_fractional_outputs;
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
+ m_track_uses = field_track_uses;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
@@ -4423,6 +4511,23 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
bool wallet2::finalize_multisig(const epee::wipeable_string &password, const std::unordered_set<crypto::public_key> &pkeys, std::vector<crypto::public_key> signers)
{
+ bool ready;
+ uint32_t threshold, total;
+ if (!multisig(&ready, &threshold, &total))
+ {
+ MERROR("This is not a multisig wallet");
+ return false;
+ }
+ if (ready)
+ {
+ MERROR("This multisig wallet is already finalized");
+ return false;
+ }
+ if (threshold + 1 != total)
+ {
+ MERROR("finalize_multisig should only be used for N-1/N wallets, use exchange_multisig_keys instead");
+ return false;
+ }
exchange_multisig_keys(password, pkeys, signers);
return true;
}
@@ -5222,7 +5327,7 @@ void wallet2::rescan_spent()
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, 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 = " +
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(n_outputs));
@@ -5267,6 +5372,10 @@ void wallet2::rescan_blockchain(bool hard, bool refresh)
m_transfers.clear();
m_key_images.clear();
m_pub_keys.clear();
+ m_unconfirmed_txs.clear();
+ m_payments.clear();
+ m_confirmed_txs.clear();
+ m_unconfirmed_payments.clear();
m_scanned_pool_txs[0].clear();
m_scanned_pool_txs[1].clear();
@@ -5551,7 +5660,7 @@ void wallet2::commit_tx(pending_tx& ptx)
m_daemon_rpc_mutex.unlock();
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, ores.status, ores.error);
+ THROW_WALLET_EXCEPTION_IF(ores.status != "OK" && ores.status != "success" , error::tx_rejected, ptx.tx, get_rpc_status(ores.status), ores.error);
}
else
{
@@ -5565,7 +5674,7 @@ void wallet2::commit_tx(pending_tx& ptx)
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
- THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, daemon_send_resp.status, daemon_send_resp.reason);
+ THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, get_rpc_status(daemon_send_resp.status), get_text_reason(daemon_send_resp));
// sanity checks
for (size_t idx: ptx.selected_transfers)
{
@@ -6456,7 +6565,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange");
THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange");
- THROW_WALLET_EXCEPTION_IF(getbh_res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, getbh_res.status);
+ THROW_WALLET_EXCEPTION_IF(getbh_res.status != CORE_RPC_STATUS_OK, error::get_blocks_error, get_rpc_status(getbh_res.status));
if (getbh_res.headers.size() != N)
{
MERROR("Bad blockheaders size");
@@ -6918,7 +7027,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
- THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status);
+ THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, get_rpc_status(resp_t.status));
}
// if we want to segregate fake outs pre or post fork, get distribution
@@ -6941,7 +7050,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_distribution");
- THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_output_distribution, resp_t.status);
+ THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_output_distribution, get_rpc_status(resp_t.status));
// check we got all data
for(size_t idx: selected_transfers)
@@ -7340,7 +7449,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_outs_error, daemon_resp.status);
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, 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 = " +
std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(req.outputs.size()));
@@ -10488,7 +10597,10 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err) const
boost::optional<std::string> result = m_node_rpc_proxy.get_height(height);
if (result)
{
- err = *result;
+ if (m_trusted_daemon)
+ err = *result;
+ else
+ err = "daemon error";
return 0;
}
@@ -10503,7 +10615,10 @@ uint64_t wallet2::get_daemon_blockchain_target_height(string &err)
const auto result = m_node_rpc_proxy.get_target_height(target_height);
if (result && *result != CORE_RPC_STATUS_OK)
{
- err= *result;
+ if (m_trusted_daemon)
+ err = *result;
+ else
+ err = "daemon error";
return 0;
}
return target_height;
@@ -10771,23 +10886,23 @@ bool wallet2::export_key_images(const std::string &filename) const
}
//----------------------------------------------------------------------------------------------------
-std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images() const
+std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const
{
PERF_TIMER(export_key_images_raw);
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
size_t offset = 0;
- while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_requested)
- ++offset;
+ if (!all)
+ {
+ while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_requested)
+ ++offset;
+ }
ski.reserve(m_transfers.size() - offset);
for (size_t n = offset; n < m_transfers.size(); ++n)
{
const transfer_details &td = m_transfers[n];
- crypto::hash hash;
- crypto::cn_fast_hash(&td.m_key_image, sizeof(td.m_key_image), hash);
-
// get ephemeral public key
const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index];
THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error,
@@ -11944,7 +12059,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
else if (res.status == CORE_RPC_STATUS_BUSY)
oss << "daemon is busy";
else
- oss << res.status;
+ oss << get_rpc_status(res.status);
throw std::runtime_error(oss.str());
}
cryptonote::block blk_min, blk_mid, blk_max;
@@ -12163,4 +12278,27 @@ void wallet2::on_passphrase_request(bool on_device, epee::wipeable_string & pass
if (0 != m_callback)
m_callback->on_passphrase_request(on_device, passphrase);
}
+//----------------------------------------------------------------------------------------------------
+std::string wallet2::get_rpc_status(const std::string &s) const
+{
+ if (m_trusted_daemon)
+ return s;
+ return "<error>";
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::throw_on_rpc_response_error(const boost::optional<std::string> &status, const char *method) const
+{
+ // no error
+ if (!status)
+ return;
+
+ MERROR("RPC error: " << method << ": status " << *status);
+
+ // empty string -> not connection
+ THROW_WALLET_EXCEPTION_IF(status->empty(), tools::error::no_connection_to_daemon, method);
+
+ THROW_WALLET_EXCEPTION_IF(*status == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, method);
+ THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, m_trusted_daemon ? *status : "daemon error");
+}
+
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index ace01a235..364e31483 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -273,6 +273,7 @@ namespace tools
bool m_key_image_partial;
std::vector<rct::key> m_multisig_k;
std::vector<multisig_info> m_multisig_info; // one per other participant
+ std::vector<std::pair<uint64_t, crypto::hash>> m_uses;
bool is_rct() const { return m_rct; }
uint64_t amount() const { return m_amount; }
@@ -297,6 +298,7 @@ namespace tools
FIELD(m_key_image_partial)
FIELD(m_multisig_k)
FIELD(m_multisig_info)
+ FIELD(m_uses)
END_SERIALIZE()
};
@@ -984,6 +986,8 @@ namespace tools
void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; }
bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; }
void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; }
+ bool track_uses() const { return m_track_uses; }
+ void track_uses(bool value) { m_track_uses = value; }
const std::string & device_name() const { return m_device_name; }
void device_name(const std::string & device_name) { m_device_name = device_name; }
const std::string & device_derivation_path() const { return m_device_derivation_path; }
@@ -1109,7 +1113,7 @@ namespace tools
std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
bool export_key_images(const std::string &filename) const;
- std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images() const;
+ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const;
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
bool import_key_images(std::vector<crypto::key_image> key_images);
@@ -1249,8 +1253,8 @@ namespace tools
* \param password Password of wallet file
*/
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
- void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data);
- 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);
+ void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, 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);
+ 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);
void detach_blockchain(uint64_t height);
void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const;
bool clear();
@@ -1258,7 +1262,7 @@ namespace tools
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
- void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added);
+ void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers) const;
bool prepare_file_names(const std::string& file_path);
void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
@@ -1312,6 +1316,7 @@ namespace tools
std::unordered_set<crypto::public_key> &pkeys) const;
void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const;
+ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> create_output_tracker_cache() const;
void setup_new_blockchain();
void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
@@ -1321,6 +1326,9 @@ namespace tools
void on_pin_request(epee::wipeable_string & pin);
void on_passphrase_request(bool on_device, epee::wipeable_string & passphrase);
+ std::string get_rpc_status(const std::string &s) const;
+ void throw_on_rpc_response_error(const boost::optional<std::string> &status, const char *method) const;
+
cryptonote::account_base m_account;
boost::optional<epee::net_utils::http::login> m_daemon_login;
std::string m_daemon_address;
@@ -1395,6 +1403,7 @@ namespace tools
bool m_key_reuse_mitigation2;
uint64_t m_segregation_height;
bool m_ignore_fractional_outputs;
+ bool m_track_uses;
bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
@@ -1444,7 +1453,7 @@ namespace tools
};
}
BOOST_CLASS_VERSION(tools::wallet2, 27)
-BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 10)
+BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
@@ -1593,6 +1602,9 @@ namespace boost
return;
}
a & x.m_key_image_requested;
+ if (ver < 11)
+ return;
+ a & x.m_uses;
}
template <class Archive>
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index d7dc2914e..dd65ee7fe 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -2495,7 +2495,7 @@ namespace tools
if (!m_wallet) return not_open(er);
try
{
- std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images();
+ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
res.offset = ski.first;
res.signed_key_images.resize(ski.second.size());
for (size_t n = 0; n < ski.second.size(); ++n)
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index afb8c6e91..f0c1a4e9d 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 6
+#define WALLET_RPC_VERSION_MINOR 7
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@@ -1565,7 +1565,10 @@ namespace wallet_rpc
{
struct request
{
+ bool all;
+
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_OPT(all, false);
END_KV_SERIALIZE_MAP()
};
diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp
index 84254cfdb..455bb1efa 100644
--- a/tests/core_tests/chaingen_main.cpp
+++ b/tests/core_tests/chaingen_main.cpp
@@ -229,10 +229,10 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_multisig_tx_valid_25_1_2_many_inputs);
GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_234);
GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_234_many_inputs);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_24_1_no_signers);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_25_1_no_signers);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_no_signers);
- GENERATE_AND_PLAY(gen_multisig_tx_valid_48_1_23_no_threshold);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_24_1_no_signers);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_25_1_no_signers);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_48_1_no_signers);
+ GENERATE_AND_PLAY(gen_multisig_tx_invalid_48_1_23_no_threshold);
GENERATE_AND_PLAY(gen_bp_tx_valid_1);
GENERATE_AND_PLAY(gen_bp_tx_invalid_1_1);
diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp
index fe5feb942..46ba997be 100644
--- a/tests/core_tests/multisig.cpp
+++ b/tests/core_tests/multisig.cpp
@@ -644,28 +644,28 @@ bool gen_multisig_tx_invalid_45_5_23_no_threshold::generate(std::vector<test_eve
return generate_with(events, 2, mixin, amount_paid, false, 4, 5, 5, {2, 3}, NULL, NULL);
}
-bool gen_multisig_tx_valid_24_1_no_signers::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_24_1_no_signers::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
return generate_with(events, 2, mixin, amount_paid, false, 2, 4, 1, {}, NULL, NULL);
}
-bool gen_multisig_tx_valid_25_1_no_signers::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_25_1_no_signers::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
return generate_with(events, 2, mixin, amount_paid, false, 2, 5, 1, {}, NULL, NULL);
}
-bool gen_multisig_tx_valid_48_1_no_signers::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_48_1_no_signers::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
return generate_with(events, 2, mixin, amount_paid, false, 4, 8, 1, {}, NULL, NULL);
}
-bool gen_multisig_tx_valid_48_1_23_no_threshold::generate(std::vector<test_event_entry>& events) const
+bool gen_multisig_tx_invalid_48_1_23_no_threshold::generate(std::vector<test_event_entry>& events) const
{
const size_t mixin = 4;
const uint64_t amount_paid = 10000;
diff --git a/tests/core_tests/multisig.h b/tests/core_tests/multisig.h
index 9e4cb3a23..e0d227840 100644
--- a/tests/core_tests/multisig.h
+++ b/tests/core_tests/multisig.h
@@ -234,26 +234,26 @@ struct gen_multisig_tx_invalid_45_5_23_no_threshold: public gen_multisig_tx_vali
};
template<> struct get_test_options<gen_multisig_tx_invalid_45_5_23_no_threshold>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_24_1_no_signers: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_24_1_no_signers: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_24_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_24_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_25_1_no_signers: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_25_1_no_signers: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_25_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_25_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_48_1_no_signers: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_48_1_no_signers: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_48_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_48_1_no_signers>: public get_test_options<gen_multisig_tx_validation_base> {};
-struct gen_multisig_tx_valid_48_1_23_no_threshold: public gen_multisig_tx_validation_base
+struct gen_multisig_tx_invalid_48_1_23_no_threshold: public gen_multisig_tx_validation_base
{
bool generate(std::vector<test_event_entry>& events) const;
};
-template<> struct get_test_options<gen_multisig_tx_valid_48_1_23_no_threshold>: public get_test_options<gen_multisig_tx_validation_base> {};
+template<> struct get_test_options<gen_multisig_tx_invalid_48_1_23_no_threshold>: public get_test_options<gen_multisig_tx_validation_base> {};
diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp
index ffe500d21..7e5b73415 100644
--- a/tests/functional_tests/transactions_flow_test.cpp
+++ b/tests/functional_tests/transactions_flow_test.cpp
@@ -29,6 +29,7 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/random_generator.hpp>
#include <unordered_map>
diff --git a/tests/fuzz/levin.cpp b/tests/fuzz/levin.cpp
index d0c5803f5..573abd1d3 100644
--- a/tests/fuzz/levin.cpp
+++ b/tests/fuzz/levin.cpp
@@ -65,22 +65,22 @@ namespace
{
}
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, test_levin_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_levin_connection_context& context)
{
m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
buff_out = m_invoke_out_buf;
return m_return_code;
}
- virtual int notify(int command, const std::string& in_buff, test_levin_connection_context& context)
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, test_levin_connection_context& context)
{
m_notify_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
return m_return_code;
}
diff --git a/tests/net_load_tests/net_load_tests.h b/tests/net_load_tests/net_load_tests.h
index 7e92c21b9..6c4f7cb76 100644
--- a/tests/net_load_tests/net_load_tests.h
+++ b/tests/net_load_tests/net_load_tests.h
@@ -33,6 +33,7 @@
#include <atomic>
#include <boost/asio/io_service.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include "include_base_utils.h"
#include "string_tools.h"
@@ -62,7 +63,7 @@ namespace net_load_tests
{
}
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, test_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_connection_context& context)
{
//m_invoke_counter.inc();
//std::unique_lock<std::mutex> lock(m_mutex);
@@ -73,7 +74,7 @@ namespace net_load_tests
return LEVIN_OK;
}
- virtual int notify(int command, const std::string& in_buff, test_connection_context& context)
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, test_connection_context& context)
{
//m_notify_counter.inc();
//std::unique_lock<std::mutex> lock(m_mutex);
diff --git a/tests/unit_tests/epee_levin_protocol_handler_async.cpp b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
index 10e62c167..9ea71875b 100644
--- a/tests/unit_tests/epee_levin_protocol_handler_async.cpp
+++ b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
@@ -56,22 +56,22 @@ namespace
{
}
- virtual int invoke(int command, const std::string& in_buff, std::string& buff_out, test_levin_connection_context& context)
+ virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, test_levin_connection_context& context)
{
m_invoke_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
buff_out = m_invoke_out_buf;
return m_return_code;
}
- virtual int notify(int command, const std::string& in_buff, test_levin_connection_context& context)
+ virtual int notify(int command, const epee::span<const uint8_t> in_buff, test_levin_connection_context& context)
{
m_notify_counter.inc();
boost::unique_lock<boost::mutex> lock(m_mutex);
m_last_command = command;
- m_last_in_buf = in_buff;
+ m_last_in_buf = std::string((const char*)in_buff.data(), in_buff.size());
return m_return_code;
}
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index c384ce9a5..75cf2fdd4 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -46,6 +46,7 @@
#include "hex.h"
#include "net/net_utils_base.h"
#include "net/local_ip.h"
+#include "net/buffer.h"
#include "p2p/net_peerlist_boost_serialization.h"
#include "span.h"
#include "string_tools.h"
@@ -764,3 +765,71 @@ TEST(NetUtils, PrivateRanges)
ASSERT_EQ(is_local("0.0.30.172"), false);
ASSERT_EQ(is_local("0.0.30.127"), false);
}
+
+TEST(net_buffer, basic)
+{
+ epee::net_utils::buffer buf;
+
+ ASSERT_EQ(buf.size(), 0);
+ EXPECT_THROW(buf.span(1), std::runtime_error);
+ buf.append("a", 1);
+ epee::span<const uint8_t> span = buf.span(1);
+ ASSERT_EQ(span.size(), 1);
+ ASSERT_EQ(span.data()[0], 'a');
+ EXPECT_THROW(buf.span(2), std::runtime_error);
+ buf.append("bc", 2);
+ buf.erase(1);
+ EXPECT_THROW(buf.span(3), std::runtime_error);
+ span = buf.span(2);
+ ASSERT_EQ(span.size(), 2);
+ ASSERT_EQ(span.data()[0], 'b');
+ ASSERT_EQ(span.data()[1], 'c');
+ buf.erase(1);
+ EXPECT_THROW(buf.span(2), std::runtime_error);
+ span = buf.span(1);
+ ASSERT_EQ(span.size(), 1);
+ ASSERT_EQ(span.data()[0], 'c');
+ EXPECT_THROW(buf.erase(2), std::runtime_error);
+ buf.erase(1);
+ EXPECT_EQ(buf.size(), 0);
+ EXPECT_THROW(buf.span(1), std::runtime_error);
+}
+
+TEST(net_buffer, existing_capacity)
+{
+ epee::net_utils::buffer buf;
+
+ buf.append("123456789", 9);
+ buf.erase(9);
+ buf.append("abc", 3);
+ buf.append("def", 3);
+ ASSERT_EQ(buf.size(), 6);
+ epee::span<const uint8_t> span = buf.span(6);
+ ASSERT_TRUE(!memcmp(span.data(), "abcdef", 6));
+}
+
+TEST(net_buffer, reallocate)
+{
+ epee::net_utils::buffer buf;
+
+ buf.append(std::string(4000, ' ').c_str(), 4000);
+ buf.append(std::string(8000, '0').c_str(), 8000);
+ ASSERT_EQ(buf.size(), 12000);
+ epee::span<const uint8_t> span = buf.span(12000);
+ ASSERT_TRUE(!memcmp(span.data(), std::string(4000, ' ').c_str(), 4000));
+ ASSERT_TRUE(!memcmp(span.data() + 4000, std::string(8000, '0').c_str(), 8000));
+}
+
+TEST(net_buffer, move)
+{
+ epee::net_utils::buffer buf;
+
+ buf.append(std::string(400, ' ').c_str(), 400);
+ buf.erase(399);
+ buf.append(std::string(4000, '0').c_str(), 4000);
+ ASSERT_EQ(buf.size(), 4001);
+ epee::span<const uint8_t> span = buf.span(4001);
+ ASSERT_TRUE(!memcmp(span.data(), std::string(1, ' ').c_str(), 1));
+ ASSERT_TRUE(!memcmp(span.data() + 1, std::string(4000, '0').c_str(), 4000));
+}
+
diff --git a/tests/unit_tests/test_peerlist.cpp b/tests/unit_tests/test_peerlist.cpp
index c6572c6c2..f638c6251 100644
--- a/tests/unit_tests/test_peerlist.cpp
+++ b/tests/unit_tests/test_peerlist.cpp
@@ -42,7 +42,7 @@ TEST(peer_list, peer_list_general)
#define ADD_GRAY_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr = addr_; ple.id = id_;plm.append_with_peer_gray(ple);}
#define ADD_WHITE_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr = addr_; ple.id = id_;plm.append_with_peer_white(ple);}
-#define PRINT_HEAD(step) {std::list<nodetool::peerlist_entry> bs_head; bool r = plm.get_peerlist_head(bs_head, 100);std::cout << "step " << step << ": " << bs_head.size() << std::endl;}
+#define PRINT_HEAD(step) {std::vector<nodetool::peerlist_entry> bs_head; bool r = plm.get_peerlist_head(bs_head, 100);std::cout << "step " << step << ": " << bs_head.size() << std::endl;}
ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,1, 8080), 121241, 34345);
ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,2, 8080), 121241, 34345);
@@ -58,7 +58,7 @@ TEST(peer_list, peer_list_general)
size_t gray_list_size = plm.get_gray_peers_count();
ASSERT_EQ(gray_list_size, 1);
- std::list<nodetool::peerlist_entry> bs_head;
+ std::vector<nodetool::peerlist_entry> bs_head;
bool r = plm.get_peerlist_head(bs_head, 100);
std::cout << bs_head.size() << std::endl;
ASSERT_TRUE(r);
@@ -78,7 +78,7 @@ TEST(peer_list, merge_peer_lists)
//ADD_NODE_TO_PL("\2", \3, 0x\1, (1353346618 -(\4*60*60*24+\5*60*60+\6*60+\7 )));\n
nodetool::peerlist_manager plm;
plm.init(false);
- std::list<nodetool::peerlist_entry> outer_bs;
+ std::vector<nodetool::peerlist_entry> outer_bs;
#define ADD_NODE_TO_PL(ip_, port_, id_, timestamp_) { nodetool::peerlist_entry ple; epee::string_tools::get_ip_int32_from_string(ple.adr.ip, ip_); ple.last_seen = timestamp_; ple.adr.port = port_; ple.id = id_;outer_bs.push_back(ple);}
diff --git a/tests/unit_tests/testdb.h b/tests/unit_tests/testdb.h
index 5d9ba5833..b8fef8ed3 100644
--- a/tests/unit_tests/testdb.h
+++ b/tests/unit_tests/testdb.h
@@ -89,14 +89,14 @@ public:
virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; }
virtual uint64_t get_num_outputs(const uint64_t& amount) const { return 1; }
virtual uint64_t get_indexing_base() const { return 0; }
- virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) { return cryptonote::output_data_t(); }
+ virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const { return cryptonote::output_data_t(); }
virtual cryptonote::tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return cryptonote::tx_out_index(); }
virtual cryptonote::tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const { return cryptonote::tx_out_index(); }
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<cryptonote::tx_out_index> &indices) const {}
- virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) {}
+ virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) const {}
virtual bool can_thread_bulk_indices() const { return false; }
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const { return std::vector<uint64_t>(); }
- virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector<uint64_t>(); }
+ virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const { return std::vector<std::vector<uint64_t>>(); }
virtual bool has_key_image(const crypto::key_image& img) const { return false; }
virtual void remove_block() { }
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const cryptonote::transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) {return 0;}
diff --git a/utils/gpg_keys/erciccione.asc b/utils/gpg_keys/erciccione.asc
new file mode 100644
index 000000000..109941d55
--- /dev/null
+++ b/utils/gpg_keys/erciccione.asc
@@ -0,0 +1,30 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFohQ30BCADktKHeTg48Dm4oU9JPrfHXzY3sZtTQsqsQGmYiFT8nQjRnSzic
+dZe4sh2W4UYQSLFw7pEb7a51ZYkz5+gFKcj3NmIaEpNra7+SEtszoS3IALHUyGGQ
++nFDxUHwTV5OeIUXPHs2AnCVZa4yEWmavXFiPL35+dcFkwyUA5psd97dFIbtkPQ4
+nT2RCc2emy6NHVE5L7pzlBe9CeFkFyovs847d3WDa/96TT4JMRm34qvUrSvOkqti
+xrui8hGwNedAw64ObiJhQLa3rvQ8bCtTLNHhpdc+zhBi3L5nIdwquMd5Bd6zHfmW
+HHyXEoRTZYMRabNBSR9FrsjGBiHG9wuEK2B7ABEBAAG0NWVyY2ljY2lvbmVAcHJv
+dG9ubWFpbC5jb20gPGVyY2ljY2lvbmVAcHJvdG9ubWFpbC5jb20+iQE1BBABCAAp
+BQJaIUN9BgsJBwgDAgkQdir4xgjlbN8EFQgKAgMWAgECGQECGwMCHgEAAFc+CAC2
+7BDCYPWfXCKtaqP/jzay46nai66hSyuIJ2sd4RSbQlVNCwFUQ2NtUwDxtzdzB3bk
+AfsqrkdSS7V82bfZPOoYapWikjA3LGd2GHvClKNmIgIg3CvrAByD9okhLYOmxChU
+5/FzMgSgDdbez4Z+XXzUothirHcHR7J+PtzqMZWusuyNqfXlWgPNPbAHG/hm5RLw
+s6uGOLDqhJDiqi0HjC/p9ponPAJ3g0jfECnXFp7R32EgbBHExT/g8e3L4J3Q8y/E
+WrZiQsIc89srANw5YIcjlr/i3PY8tyrelpLDVBj05802WYamYx10Zd2epM4NglBs
++YjiWpSM9fTi9QKFCHyAuQENBFohQ30BCADe4FJcus4e3FzsagKdAM/iFeZ4BE2l
+gVgSg8CVWIYlTAmeK+SBPfsxvwOWxmx/KkirWn3hOSA2U6mp9+g6hr9rLqWNwatM
+OsitrJlWG2aPcuAmlzLFvtH0Vbilh0m4B98g2XUa94HtrlGdPAoYPquS1HsfL284
+CHpQXXOypOS+/spTK/OlpdUaPaVyqVfE3kzXYqt24RbDcsOvUzSzVRCA8kBp6azm
+1qoqDboP112Ax7OkV0FGc/kd5PNMPTOnVR+4wVXWhl6gAI1I2JFvo3EJlxtddyTB
+Rkx06jbYRyPj9KCEC4CBx9qsNlo7TUHgObAr+CLX4I5hkEWW0pS98vlpABEBAAGJ
+AR8EGAEIABMFAlohQ30JEHYq+MYI5WzfAhsMAAD1twgAxjbETzOUeq/bWwVoGzmh
+SMJajZs2c5Pv0SAwi5QZCoRefp2HYfpWcBsfZG84B0EmJb9Wwu3wrXWBf96xMTFM
+neU0+L2+RcH8uH7/C2MlVaZjFv5dPPJAtwbY2BQl1bX5DrEwZ8QH7IUXZmWfjmZ3
+ww5llfCAyVCxMn+tnIJnk/7HODY0t1LmusFvZsAVsWIgdndKImXM4CTzirfmDks8
+TxpXfaJzU3B3KTIzMgEvwtTLJfgf07Foy4ITIl+1zS7gLL0fXldtx6fJJMvANsLf
+JrRjafh21qfJb3I9TUH8G7C0Ln3LspBGsWZ4f+fjq4LEg7SCOAJSeBwfOtMJeCrU
+/Q==
+=a70Z
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/utils/gpg_keys/moneromooo.asc b/utils/gpg_keys/moneromooo.asc
index cce180937..4275b6c0e 100644
--- a/utils/gpg_keys/moneromooo.asc
+++ b/utils/gpg_keys/moneromooo.asc
@@ -13,18 +13,18 @@ p7gDvxXOGxzq0sqfPTWTBdCj1OPfunHbbeH8ypwBlNpwVG40fJdya+Dqjwu25qX6
Xh5vxLzeJTBmlawa97MCliPvzzJgW9qHRVCa9lLloGVYLiUOS0N+dZ/r/QARAQAB
tD5tb25lcm9tb29vLW1vbmVybyA8bW9uZXJvbW9vby1tb25lcm9AdXNlcnMubm9y
ZXBseS5naXRodWIuY29tPokCPwQTAQIAKQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMB
-Ah4BAheABQJbof8TBQkLMcqRAAoJEGhvB0VNbO/DOrcP/1eG3gkIgq+lXKlv/lta
-ZFl8jS5iQUwxTHv8s+O7pbL2mwKt5oM8QmXVMFLlaanENmH0y/DhWRYIYuKTifDN
-tXOxENCZhxgjlVxAtnMdD2J8MJANzV2MYGLbGQeFAuZHIL2LMfvUENLYx/jJpe7f
-93kXZoQio7rIolnlbM1QoJLxi/7HlOt/VsopJlV2wAmOmlpyWDnOZtUtZgiCGV6a
-apFzTs2m3n2GP7+8PG/W01/jVyFqixGW8cWVZORBMhjro2JqrRvw7U+Ypk2o7Em4
-SAnAJyzqpTDh9zf0QWkQXN83YThB3dk1M1FXOyKtZ8G+YVNfs5Ldr7tHNbqKi2v8
-lPaPIDQ7UmxZhy9vraKss0/3AEXaiE2eSvLc4eCcLiS4yVQ2KJpK5TUvz3cP1D5C
-USsjxUZvolUELBtNaRVAsxX6OAyA8FjwJ8AKCqyR0NHvrbYhj54N1Js8PWtb+qqk
-5sBLKOwEPaWM1uG6SJabrY1xu2VNLOGdJA9bRfyyzfpXksD0lFgwLKki6ReqqoMS
-QiVdymhcp55J4tFwsDkzJX7296d1x3r7GAIQMLNc7YizukWfNtvUkSUsAwp+RKUx
-TTwkwL1ztzSRpt3hGMJ9SfULTaQD7YAYfz4kitMBNpm90CLFa4CeINu98gE9Ogmc
-R+CGQOHLUC3rXubgRCiQg5wfuQINBFQym34BEADHtTHduZFdu76RAzqTjT94F92L
+Ah4BAheABQJcEB4SBQkLn+mRAAoJEGhvB0VNbO/DzSIQALXk6ST5Uoxh5+NLBJgI
+GR2NOCFwsU+97VOkZWZnzpk+JdUrq/I9JmWWTegGKu3it5YvM8xY1zD1l+RXlnmY
+Bg7oT6N63lL8hBhxGm9Hk2A1VJlEjtgtvjbg5yLSdvjxJL1vrmchWGwFWoHT9uIh
+oefemb3TQ1U+ADVsW42jXca650/rqvsUMpmQbDfHxUBIfpbxgTWz8sHuMfhFB3R0
+nzSuZ1E1Pbg5jWYxd6sXpb1VFZ7TaQNVGB+4wMe8AH8/0qziLVTXvSkoer6qxU+r
+e9M9/Rgue1FJSzZogUekIqyNLsvAeATSCYzi8NoywkUbAq6AqazJtdcOD+7M2/Vl
+pdQEnIKSO/9xrziUQifRsPx4LOjf2d2Hvor/rBJYwoI1cFgR5pmH30Mi7OY0mMmm
+2TMUPPz7YiVY+RPPpY3Mg5oPRe6sHVAdFYBmc0PTR4v92iYgfQXzoCd5HOJI9QB3
+SwrKz7cNLQwob2za1AXZ3sUp+yok6QMt8Tk6xIbMAjeR4jVeP8iQHhiVS1zx5z/g
+lCAfb0hJnykoANgIZvJR/L+tuZjVStqnXjHgreY3IjlWTaNjZ/X5uMvd6zivqI9a
+aEmqw/ZDCXRMAtjUCpUvpNlqAgqqbQsx6MFDnMbd4BuKQONeAFLm/Rp31nIvt1vb
++Iu3vkXBbbjb5yMu/dcpgSRUuQINBFQym34BEADHtTHduZFdu76RAzqTjT94F92L
xSSopLSk7/sdLWTc2ERmjDId7dKmqrL1Kh2kqAtHY3Rq8Y839LGmbJCzI1kJyOHF
o9jkEI93sqXcztLjizPVukqClOZNt3NV/nvefH6JSdqWcnC4V1mQr2Ztl0j+51i+
NYVwGjlsOMlBER+LW/s7egRqAQonrcEB5vsSAzd8mOlNKjRAnDCV+C21GDKxzb80
@@ -35,17 +35,17 @@ xRFfhoiiPyjjPRmJ+/iG3KXLzEiMfbyTFzGkX3Z9BJTxemUx8JOSVQXa++t4w39J
UwzwBKNItDhtQqJpCaF43fJ4ykLMJi5gRpgqtb+T3CF0abXNII1IfS8a0fSpd48d
6hzoCVqpvWsI1fOY5Ui0BIgubNhkr4OJDCWBT5zhxjCJ3QiUSKyyqjfw1Fpuf/0Y
CSA9Q9FSCq9qTppJs5ITHVjhWw2zxrJEG+P2+dvryBhV9l4T2xx1oHqlKX8zzLBG
-kS8NmnxoRFQs5rZYvQARAQABiQIlBBgBAgAPAhsMBQJX3tl5BQkHbqT4AAoJEGhv
-B0VNbO/DrN4QAJVTg2l91LSxb2dTikXbkRCPev1Eiqjd3d4TZIyE7yeYreHUyfcz
-sytEsMUpd5nqqL/QMOwgC8Dm+77Yp480atI/c0wQh30EfJq1YP4q/gwv8EtriFo6
-ZaqYNzajmB8otz6yyb5RD9S6ocZX5b22nnNM/ihiTQJiqJKC2XHPQH3/grniU9if
-WXUlY7Fo+8lRn/aRPMjYT2elsugru8GoplDMyfPRymnMJmTwNPYkg0Dnm2JUXYhH
-VLO6Ebh7fUChsiGNmSp+siv7fcZIf20+LvoymgyT+49LrrQMvRleOqaJc1LBKaK6
-1yU+jLk1f9bFCMORQoTxvIVaSnjMWAeKDxi8nwuVfUJpQYXmbOOqMZgoFi6t+U7/
-T6Cz1CGKv3JgEveWyHeOvsjopej3a4Hmk7QGM/xJrd83roUjypjx5lTeMDvcPlPs
-IQOy33qWguR1xoEnwAp9ov/meS7HtUOoC0m9ROZqWT6ArN+1ONplFP4GTsuW91Qz
-pacQMl09F0KF1MacAdpauCOKj+wy9XPUW8v3kWZufUSgNtOLHS+kVumkqdJuJ0aB
-7Ezc1yYY6DwRFOdlUpTJkRMozyPRvS15Lz/vPEhcbxMHRAg611CS2CqTEIbk2chJ
-QBlj77a45lDTXGQHFVYXlbXx/HWb5zOGpNji0QhY1hOABRo78DT5yda+
-=ksQj
+kS8NmnxoRFQs5rZYvQARAQABiQIlBBgBAgAPAhsMBQJcEB4eBQkLn+meAAoJEGhv
+B0VNbO/DjzYP/2A6HtpvPkD+s/0+Ghmp5Rw7HIvZz0RnCsvM3qVQqVn3JTqHXyhD
+5GmZrCxhliW1nRBITaKSRHXSGeE/O1BtK6eW/Z1P6bWJVd+R9vhaZlLU2sswiFzu
+q3s7bL/Fo9VRc0SX6j6JDh1FZ3JcebUfY59sixHLqZuAk9m97z6H1NjS+f4pB5Tp
+n1nnRgdvYk4tjlk4mmluIAwjq8Ll6gw6ntwjX9Gq9OblutTr2MZDyTIOxcG54ZN2
+2t5JA7Syh0He6dn/NLlb//bPPnic3GuYfkgKht8M1XCJfnDKju+I9qRGf1DYIjP7
+m24IDC0MM9Fo7KIUY+vcV0J/BIkkZtZ9xh0iEEnR/KqYXmClym+EiWCwPhLloKL3
+6cZr5MaiYJsodYa73x35pSGvioUrBDb78v8nCNhoTUXzZv8E0s/0YI2UZSGhVEC6
+ANNXPvKeOdibGNDM4JOwETabkEng38UE6Oa7Qonra2MWsPegh+mnZ7/sqrktQRMB
+T/Xne6vapDONeLeY2hVcT0j9f/S8rgpHPjP4/hmYE9d38Euwa7TZ0lHWcmJzQy6F
+7HfGR3oYAYAwRnvl+kYUGZ46u9Nodi4+wycFc4+IpwFtnlUzRBOcOilnR2X6KFJW
+SiVss1i7ECcWaKCBNN1MrpwGWeuSbCQ00c3bxe6ZN6goB1t2u1KAZqMK
+=HFHX
-----END PGP PUBLIC KEY BLOCK-----