aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md8
-rw-r--r--cmake/FindLibUSB.cmake11
-rw-r--r--contrib/brew/Brewfile34
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.h3
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl8
-rw-r--r--contrib/epee/include/net/http_client.h12
-rw-r--r--contrib/epee/include/net/net_helper.h7
-rw-r--r--external/easylogging++/easylogging++.cc48
-rw-r--r--external/easylogging++/easylogging++.h15
-rw-r--r--src/blockchain_db/blockchain_db.cpp4
-rw-r--r--src/blockchain_db/blockchain_db.h55
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp76
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h11
-rw-r--r--src/blockchain_db/testdb.h10
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp6
-rw-r--r--src/cryptonote_basic/hardfork.cpp30
-rw-r--r--src/cryptonote_basic/miner.cpp1
-rw-r--r--src/cryptonote_core/CMakeLists.txt2
-rw-r--r--src/cryptonote_core/blockchain.cpp71
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp5
-rw-r--r--src/cryptonote_core/tx_sanity_check.cpp100
-rw-r--r--src/cryptonote_core/tx_sanity_check.h36
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl2
-rw-r--r--src/daemon/main.cpp7
-rw-r--r--src/daemon/rpc_command_executor.cpp4
-rw-r--r--src/p2p/net_node.inl9
-rw-r--r--src/ringct/bulletproofs.cc62
-rw-r--r--src/ringct/rctSigs.cpp1
-rw-r--r--src/ringct/rctTypes.h2
-rw-r--r--src/rpc/core_rpc_server.cpp41
-rw-r--r--src/rpc/core_rpc_server.h3
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h18
-rw-r--r--src/rpc/daemon_handler.cpp2
-rw-r--r--src/simplewallet/simplewallet.cpp10
-rw-r--r--src/wallet/node_rpc_proxy.cpp13
-rw-r--r--src/wallet/node_rpc_proxy.h6
-rw-r--r--src/wallet/wallet2.cpp157
-rw-r--r--src/wallet/wallet2.h17
-rw-r--r--src/wallet/wallet_rpc_server.cpp97
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h14
-rwxr-xr-xtests/block_weight/block_weight.py5
-rw-r--r--tests/core_tests/bulletproofs.h2
-rw-r--r--tests/core_tests/chaingen.h23
-rw-r--r--tests/core_tests/multisig.h2
-rw-r--r--tests/core_tests/rct.h2
-rwxr-xr-xtests/functional_tests/transfer.py50
-rw-r--r--tests/trezor/trezor_tests.cpp2
-rw-r--r--tests/unit_tests/ban.cpp29
-rw-r--r--tests/unit_tests/blockchain_db.cpp4
-rw-r--r--tests/unit_tests/long_term_block_weight.cpp17
-rw-r--r--tests/unit_tests/ringct.cpp120
-rw-r--r--tests/unit_tests/serialization.cpp79
-rw-r--r--utils/python-rpc/framework/daemon.py3
-rw-r--r--utils/python-rpc/framework/wallet.py45
55 files changed, 904 insertions, 500 deletions
diff --git a/README.md b/README.md
index 7ee787e50..c46856b17 100644
--- a/README.md
+++ b/README.md
@@ -30,10 +30,10 @@ Our researchers are available on IRC in [#monero-research-lab on Freenode](https
- You can subscribe to an [announcement listserv](https://lists.getmonero.org) to get critical announcements from the Monero core team. The announcement list can be very helpful for knowing when software updates are needed.
## Translations
-The CLI wallet is available in different languages. If you want to help translate it, join Pootle, our self-hosted localization platform: [translate.getmonero.org](https://translate.getmonero.org). Every translation *must* be uploaded on Pootle, pull requests directly editing the code on this repository will be closed.
+The CLI wallet is available in different languages. If you want to help translate it, see our self-hosted localization platform, Pootle, on [translate.getmonero.org](https://translate.getmonero.org/projects/CLI/). Every translation *must* be uploaded on the platform, pull requests directly editing the code in this repository will be closed. If you need help with Pootle, you can find a guide with screenshots [here](https://github.com/monero-ecosystem/monero-translations/blob/master/pootle.md).
 
-If you need help/support/info, contact the localization workgroup. You can do so in various ways: by email (translate[at]getmonero[dot]org), on the official chat (#monero-translations). A complete list of contacts can be found on the repository of the workgroup: [monero-ecosystem/monero-translations](https://github.com/monero-ecosystem/monero-translations#contacts).
+If you need help/support/info about translations, contact the localization workgroup. You can find the complete list of contacts on the repository of the workgroup: [monero-translations](https://github.com/monero-ecosystem/monero-translations#contacts).
## Build
@@ -180,8 +180,8 @@ Install all dependencies at once on Debian/Ubuntu:
``` sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev doxygen graphviz libpgm-dev```
-Install all dependencies at once on macOS:
-``` brew update && brew install cmake pkg-config openssl boost hidapi zmq libpgm unbound libsodium miniupnpc readline ldns expat doxygen graphviz protobuf ```
+Install all dependencies at once on macOS with the provided Brewfile:
+``` brew update && brew bundle --file=contrib/brew/Brewfile ```
FreeBSD one liner for required to build dependencies
```pkg install git gmake cmake pkgconf boost-libs cppzmq libsodium```
diff --git a/cmake/FindLibUSB.cmake b/cmake/FindLibUSB.cmake
index 7e3bf156e..c7e09d4c0 100644
--- a/cmake/FindLibUSB.cmake
+++ b/cmake/FindLibUSB.cmake
@@ -99,9 +99,18 @@ if ( LibUSB_FOUND )
check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_device_list "" LibUSB_VERSION_1.0 )
check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_port_numbers "" LibUSB_VERSION_1.0.16 )
+ if((STATIC AND UNIX AND NOT APPLE) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux"))
+ find_library(LIBUDEV_LIBRARY udev)
+ if(LIBUDEV_LIBRARY)
+ set(LibUSB_LIBRARIES "${LibUSB_LIBRARIES};${LIBUDEV_LIBRARY}")
+ else()
+ message(WARNING "libudev library not found, binaries may fail to link.")
+ endif()
+ endif()
+
# Library 1.0.16+ compilation test.
# The check_library_exists does not work well on Apple with shared libs.
- if (APPLE OR LibUSB_VERSION_1.0.16)
+ if (APPLE OR LibUSB_VERSION_1.0.16 OR STATIC)
if (APPLE)
if(DEPENDS)
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
diff --git a/contrib/brew/Brewfile b/contrib/brew/Brewfile
new file mode 100644
index 000000000..1fdf45cfe
--- /dev/null
+++ b/contrib/brew/Brewfile
@@ -0,0 +1,34 @@
+# Brewfile for Monero
+# A homebrew Brewfile installs all required dependencies in one shot
+# see https://coderwall.com/p/afmnbq/homebrew-s-new-feature-brewfiles
+# https://github.com/Homebrew/homebrew-bundle
+# execute brew bundle in the directory containing the Brewfile
+
+tap "homebrew/bundle"
+tap "homebrew/cask"
+tap "homebrew/cask-versions"
+tap "homebrew/core"
+
+brew "autoconf"
+brew "autogen"
+brew "automake"
+brew "binutils"
+brew "coreutils"
+brew "cmake"
+brew "pkg-config"
+brew "boost"
+brew "openssl"
+brew "hidapi"
+brew "zmq"
+brew "libpgm"
+brew "unbound"
+brew "libsodium"
+brew "miniupnpc"
+brew "readline"
+brew "ldns"
+brew "expat"
+brew "doxygen"
+brew "graphviz"
+brew "libunwind-headers"
+brew "xz"
+brew "protobuf"
diff --git a/contrib/epee/include/net/abstract_tcp_server2.h b/contrib/epee/include/net/abstract_tcp_server2.h
index d0eabbba5..374a28a2e 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.h
+++ b/contrib/epee/include/net/abstract_tcp_server2.h
@@ -93,11 +93,12 @@ namespace net_utils
struct shared_state : connection_basic_shared_state
{
shared_state()
- : connection_basic_shared_state(), pfilter(nullptr), config()
+ : connection_basic_shared_state(), pfilter(nullptr), config(), stop_signal_sent(false)
{}
i_connection_filter* pfilter;
typename t_protocol_handler::config_type config;
+ bool stop_signal_sent;
};
/// Construct a connection with the given io_service.
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 14fbec5d9..821594355 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -762,7 +762,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
m_timer.cancel();
boost::system::error_code ignored_ec;
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
- socket_.shutdown(ignored_ec);
+ {
+ const shared_state &state = static_cast<const shared_state&>(get_state());
+ if (!state.stop_signal_sent)
+ socket_.shutdown(ignored_ec);
+ }
socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
if (!m_host.empty())
{
@@ -1130,6 +1134,8 @@ POP_WARNINGS
void boosted_tcp_server<t_protocol_handler>::send_stop_signal()
{
m_stop_signal_sent = true;
+ typename connection<t_protocol_handler>::shared_state *state = static_cast<typename connection<t_protocol_handler>::shared_state*>(m_state.get());
+ state->stop_signal_sent = true;
TRY_ENTRY();
connections_mutex.lock();
for (auto &c: connections_)
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
index bb10c8efc..588d5f0e3 100644
--- a/contrib/epee/include/net/http_client.h
+++ b/contrib/epee/include/net/http_client.h
@@ -274,6 +274,7 @@ namespace net_utils
reciev_machine_state m_state;
chunked_state m_chunked_state;
std::string m_chunked_cache;
+ bool m_auto_connect;
critical_section m_lock;
public:
@@ -291,6 +292,7 @@ namespace net_utils
, m_state()
, m_chunked_state()
, m_chunked_cache()
+ , m_auto_connect(true)
, m_lock()
{}
@@ -316,6 +318,11 @@ namespace net_utils
m_net_client.set_ssl(std::move(ssl_options));
}
+ void set_auto_connect(bool auto_connect)
+ {
+ m_auto_connect = auto_connect;
+ }
+
template<typename F>
void set_connector(F connector)
{
@@ -367,6 +374,11 @@ namespace net_utils
CRITICAL_REGION_LOCAL(m_lock);
if(!is_connected())
{
+ if (!m_auto_connect)
+ {
+ MWARNING("Auto connect attempt to " << m_host_buff << ":" << m_port << " disabled");
+ return false;
+ }
MDEBUG("Reconnecting...");
if(!connect(timeout))
{
diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h
index e8fb40a0a..89cef8134 100644
--- a/contrib/epee/include/net/net_helper.h
+++ b/contrib/epee/include/net/net_helper.h
@@ -428,9 +428,10 @@ namespace net_utils
handler_obj hndlr(ec, bytes_transfered);
- char local_buff[10000] = {0};
+ static const size_t max_size = 16384;
+ buff.resize(max_size);
- async_read(local_buff, sizeof(local_buff), boost::asio::transfer_at_least(1), hndlr);
+ async_read(&buff[0], max_size, boost::asio::transfer_at_least(1), hndlr);
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned))
@@ -463,7 +464,7 @@ namespace net_utils
return false;*/
m_bytes_received += bytes_transfered;
- buff.assign(local_buff, bytes_transfered);
+ buff.resize(bytes_transfered);
return true;
}
diff --git a/external/easylogging++/easylogging++.cc b/external/easylogging++/easylogging++.cc
index f5f7481f8..5a806dc69 100644
--- a/external/easylogging++/easylogging++.cc
+++ b/external/easylogging++/easylogging++.cc
@@ -1,17 +1,16 @@
//
// Bismillah ar-Rahmaan ar-Raheem
//
-// Easylogging++ v9.96.5
+// Easylogging++ v9.96.7
// Cross-platform logging library for C++ applications
//
-// Copyright (c) 2012-2018 Muflihun Labs
+// Copyright (c) 2012-2018 Zuhd Web Services
// Copyright (c) 2012-2018 @abumusamq
//
// This library is released under the MIT Licence.
-// https://github.com/muflihun/easyloggingpp/blob/master/LICENSE
+// https://github.com/zuhd-org/easyloggingpp/blob/master/LICENSE
//
-// https://github.com/muflihun/easyloggingpp
-// https://muflihun.github.io/easyloggingpp
+// https://zuhd.org
// http://muflihun.com
//
@@ -962,7 +961,7 @@ void Str::replaceFirstWithEscape(base::type::string_t& str, const base::type::st
std::size_t foundAt = base::type::string_t::npos;
while ((foundAt = str.find(replaceWhat, foundAt + 1)) != base::type::string_t::npos) {
if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) {
- str.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
+ str.erase(foundAt - 1, 1);
++foundAt;
} else {
str.replace(foundAt, replaceWhat.length(), replaceWith);
@@ -1531,7 +1530,7 @@ void LogFormat::parseFromFormat(const base::type::string_t& userFormat) {
if (hasFlag(flag)) {
// If we already have flag we remove the escape chars so that '%%' is turned to '%'
// even after specifier resolution - this is because we only replaceFirst specifier
- formatCopy.erase(foundAt > 0 ? foundAt - 1 : 0, 1);
+ formatCopy.erase(foundAt - 1, 1);
++foundAt;
}
} else {
@@ -2206,20 +2205,26 @@ Storage::Storage(const LogBuilderPtr& defaultLogBuilder) :
m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)),
m_flags(ELPP_DEFAULT_LOGGING_FLAGS),
m_vRegistry(new base::VRegistry(0, &m_flags)),
+
#if ELPP_ASYNC_LOGGING
m_asyncLogQueue(new base::AsyncLogQueue()),
m_asyncDispatchWorker(asyncDispatchWorker),
#endif // ELPP_ASYNC_LOGGING
+
m_preRollOutCallback(base::defaultPreRollOutCallback) {
// Register default logger
m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId));
// We register default logger anyway (worse case it's not going to register) just in case
m_registeredLoggers->get("default");
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
// Register performance logger and reconfigure format
Logger* performanceLogger = m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId));
m_registeredLoggers->get("performance");
performanceLogger->configurations()->setGlobally(ConfigurationType::Format, std::string("%datetime %level %msg"));
performanceLogger->reconfigure();
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+
#if defined(ELPP_SYSLOG)
// Register syslog logger and reconfigure format
Logger* sysLogLogger = m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId));
@@ -2337,6 +2342,19 @@ base::threading::Mutex& LogDispatchCallback::fileHandle(const LogDispatchData* d
namespace base {
// DefaultLogDispatchCallback
+const char* convertToChar(Level level) {
+ // Do not use switch over strongly typed enums because Intel C++ compilers dont support them yet.
+ if (level == Level::Global) return "G";
+ if (level == Level::Debug) return "D";
+ if (level == Level::Info) return "I";
+ if (level == Level::Warning) return "W";
+ if (level == Level::Error) return "E";
+ if (level == Level::Fatal) return "F";
+ if (level == Level::Verbose) return "V";
+ if (level == Level::Trace) return "T";
+ return "?";
+}
+
void DefaultLogDispatchCallback::handle(const LogDispatchData* data) {
#if defined(ELPP_THREAD_SAFE)
#if 0
@@ -2345,11 +2363,15 @@ void DefaultLogDispatchCallback::handle(const LogDispatchData* data) {
#endif
#endif
m_data = data;
- dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(),
+ base::TypedConfigurations* tc = m_data->logMessage()->logger()->typedConfigurations();
+ const base::LogFormat* logFormat = &tc->logFormat(m_data->logMessage()->level());
+ dispatch(base::utils::DateTime::getDateTime(logFormat->dateTimeFormat().c_str(), &tc->subsecondPrecision(m_data->logMessage()->level()))
+ + "\t" + convertToChar(m_data->logMessage()->level()) + " " + m_data->logMessage()->message() + "\n",
+ m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(),
m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog));
}
-void DefaultLogDispatchCallback::dispatch(base::type::string_t&& logLine) {
+void DefaultLogDispatchCallback::dispatch(base::type::string_t&& rawLine, base::type::string_t&& logLine) {
if (m_data->dispatchAction() == base::DispatchAction::NormalLog || m_data->dispatchAction() == base::DispatchAction::FileOnlyLog) {
if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(m_data->logMessage()->level())) {
base::type::fstream_t* fs = m_data->logMessage()->logger()->m_typedConfigurations->fileStream(
@@ -2376,8 +2398,8 @@ void DefaultLogDispatchCallback::dispatch(base::type::string_t&& logLine) {
if (m_data->dispatchAction() != base::DispatchAction::FileOnlyLog) {
if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(m_data->logMessage()->level())) {
if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput))
- m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&logLine, m_data->logMessage()->level());
- ELPP_COUT << ELPP_COUT_LINE(logLine);
+ m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(&rawLine, m_data->logMessage()->level());
+ ELPP_COUT << ELPP_COUT_LINE(rawLine);
}
}
}
@@ -3279,11 +3301,11 @@ const std::string &Loggers::getFilenameCommonPrefix() {
// VersionInfo
const std::string VersionInfo::version(void) {
- return std::string("9.96.5");
+ return std::string("9.96.7");
}
/// @brief Release date of current version
const std::string VersionInfo::releaseDate(void) {
- return std::string("07-09-2018 0950hrs");
+ return std::string("24-11-2018 0728hrs");
}
} // namespace el
diff --git a/external/easylogging++/easylogging++.h b/external/easylogging++/easylogging++.h
index d9a2dc3d1..f0d8d5df7 100644
--- a/external/easylogging++/easylogging++.h
+++ b/external/easylogging++/easylogging++.h
@@ -1,17 +1,16 @@
//
// Bismillah ar-Rahmaan ar-Raheem
//
-// Easylogging++ v9.96.5
+// Easylogging++ v9.96.7
// Single-header only, cross-platform logging library for C++ applications
//
-// Copyright (c) 2012-2018 Muflihun Labs
+// Copyright (c) 2012-2018 Zuhd Web Services
// Copyright (c) 2012-2018 @abumusamq
//
// This library is released under the MIT Licence.
-// https://github.com/muflihun/easyloggingpp/blob/master/LICENSE
+// https://github.com/zuhd-org/easyloggingpp/blob/master/LICENSE
//
-// https://github.com/muflihun/easyloggingpp
-// https://muflihun.github.io/easyloggingpp
+// https://zuhd.org
// http://muflihun.com
//
@@ -758,10 +757,12 @@ static const char* kDefaultLoggerId = ELPP_DEFAULT_L
static const char* kDefaultLoggerId = "default";
#endif
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
#ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER
static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER;
#else
static const char* kPerformanceLoggerId = "performance";
+#endif // ELPP_DEFAULT_PERFORMANCE_LOGGER
#endif
#if defined(ELPP_SYSLOG)
@@ -2776,7 +2777,7 @@ class DefaultLogDispatchCallback : public LogDispatchCallback {
void handle(const LogDispatchData* data);
private:
const LogDispatchData* m_data;
- void dispatch(base::type::string_t&& logLine);
+ void dispatch(base::type::string_t&& rawLine, base::type::string_t&& logLine);
};
#if ELPP_ASYNC_LOGGING
class AsyncLogDispatchCallback : public LogDispatchCallback {
@@ -3836,7 +3837,7 @@ class Helpers : base::StaticClass {
return ELPP->hasCustomFormatSpecifier(formatSpecifier);
}
static inline void validateFileRolling(Logger* logger, Level level) {
- if (logger == nullptr) return;
+ if (ELPP == nullptr || logger == nullptr) return;
logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback());
}
};
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index d772bf4bb..2b039f557 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -211,8 +211,6 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
if (blk.tx_hashes.size() != txs.size())
throw std::runtime_error("Inconsistent tx/hashes sizes");
- block_txn_start(false);
-
TIME_MEASURE_START(time1);
crypto::hash blk_hash = get_block_hash(blk);
TIME_MEASURE_FINISH(time1);
@@ -252,8 +250,6 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
m_hardfork->add(blk, prev_height);
- block_txn_stop();
-
++num_calls;
return prev_height;
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 2c40b5a78..567be6a65 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -770,9 +770,12 @@ public:
*/
virtual void set_batch_transactions(bool) = 0;
- virtual void block_txn_start(bool readonly=false) = 0;
- virtual void block_txn_stop() = 0;
- virtual void block_txn_abort() = 0;
+ virtual void block_wtxn_start() = 0;
+ virtual void block_wtxn_stop() = 0;
+ virtual void block_wtxn_abort() = 0;
+ virtual bool block_rtxn_start() const = 0;
+ virtual void block_rtxn_stop() const = 0;
+ virtual void block_rtxn_abort() const = 0;
virtual void set_hard_fork(HardFork* hf);
@@ -1699,6 +1702,52 @@ public:
}; // class BlockchainDB
+class db_txn_guard
+{
+public:
+ db_txn_guard(BlockchainDB *db, bool readonly): db(db), readonly(readonly), active(false)
+ {
+ if (readonly)
+ {
+ active = db->block_rtxn_start();
+ }
+ else
+ {
+ db->block_wtxn_start();
+ active = true;
+ }
+ }
+ virtual ~db_txn_guard()
+ {
+ if (active)
+ stop();
+ }
+ void stop()
+ {
+ if (readonly)
+ db->block_rtxn_stop();
+ else
+ db->block_wtxn_stop();
+ active = false;
+ }
+ void abort()
+ {
+ if (readonly)
+ db->block_rtxn_abort();
+ else
+ db->block_wtxn_abort();
+ active = false;
+ }
+
+private:
+ BlockchainDB *db;
+ bool readonly;
+ bool active;
+};
+
+class db_rtxn_guard: public db_txn_guard { public: db_rtxn_guard(BlockchainDB *db): db_txn_guard(db, true) {} };
+class db_wtxn_guard: public db_txn_guard { public: db_wtxn_guard(BlockchainDB *db): db_txn_guard(db, false) {} };
+
BlockchainDB *new_db(const std::string& db_type);
} // namespace cryptonote
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index a07e9ac55..340434888 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -3611,16 +3611,15 @@ void BlockchainLMDB::block_rtxn_stop() const
memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
}
-void BlockchainLMDB::block_txn_start(bool readonly)
+bool BlockchainLMDB::block_rtxn_start() const
{
- if (readonly)
- {
- MDB_txn *mtxn;
- mdb_txn_cursors *mcur;
- block_rtxn_start(&mtxn, &mcur);
- return;
- }
+ MDB_txn *mtxn;
+ mdb_txn_cursors *mcur;
+ return block_rtxn_start(&mtxn, &mcur);
+}
+void BlockchainLMDB::block_wtxn_start()
+{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
// Distinguish the exceptions here from exceptions that would be thrown while
// using the txn and committing it.
@@ -3652,10 +3651,13 @@ void BlockchainLMDB::block_txn_start(bool readonly)
throw0(DB_ERROR_TXN_START((std::string("Attempted to start new write txn when batch txn already exists in ")+__FUNCTION__).c_str()));
}
-void BlockchainLMDB::block_txn_stop()
+void BlockchainLMDB::block_wtxn_stop()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- if (m_write_txn && m_writer == boost::this_thread::get_id())
+ if (!m_write_txn)
+ throw0(DB_ERROR_TXN_START((std::string("Attempted to stop write txn when no such txn exists in ")+__FUNCTION__).c_str()));
+ if (m_writer != boost::this_thread::get_id())
+ throw0(DB_ERROR_TXN_START((std::string("Attempted to stop write txn from the wrong thread in ")+__FUNCTION__).c_str()));
{
if (! m_batch_active)
{
@@ -3669,40 +3671,31 @@ void BlockchainLMDB::block_txn_stop()
memset(&m_wcursors, 0, sizeof(m_wcursors));
}
}
- else if (m_tinfo->m_ti_rtxn)
- {
- mdb_txn_reset(m_tinfo->m_ti_rtxn);
- memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- }
}
-void BlockchainLMDB::block_txn_abort()
+void BlockchainLMDB::block_wtxn_abort()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
- if (m_write_txn && m_writer == boost::this_thread::get_id())
- {
- if (! m_batch_active)
- {
- delete m_write_txn;
- m_write_txn = nullptr;
- memset(&m_wcursors, 0, sizeof(m_wcursors));
- }
- }
- else if (m_tinfo->m_ti_rtxn)
- {
- mdb_txn_reset(m_tinfo->m_ti_rtxn);
- memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- }
- else
+ if (!m_write_txn)
+ throw0(DB_ERROR_TXN_START((std::string("Attempted to abort write txn when no such txn exists in ")+__FUNCTION__).c_str()));
+ if (m_writer != boost::this_thread::get_id())
+ throw0(DB_ERROR_TXN_START((std::string("Attempted to abort write txn from the wrong thread in ")+__FUNCTION__).c_str()));
+
+ if (! m_batch_active)
{
- // This would probably mean an earlier exception was caught, but then we
- // proceeded further than we should have.
- throw0(DB_ERROR((std::string("BlockchainLMDB::") + __func__ +
- std::string(": block-level DB transaction abort called when write txn doesn't exist")
- ).c_str()));
+ delete m_write_txn;
+ m_write_txn = nullptr;
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
}
}
+void BlockchainLMDB::block_rtxn_abort() const
+{
+ LOG_PRINT_L3("BlockchainLMDB::" << __func__);
+ mdb_txn_reset(m_tinfo->m_ti_rtxn);
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+}
+
uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
const std::vector<std::pair<transaction, blobdata>>& txs)
{
@@ -3728,11 +3721,6 @@ uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t
{
throw;
}
- catch (...)
- {
- block_txn_abort();
- throw;
- }
return ++m_height;
}
@@ -3742,16 +3730,16 @@ void BlockchainLMDB::pop_block(block& blk, std::vector<transaction>& txs)
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
- block_txn_start(false);
+ block_wtxn_start();
try
{
BlockchainDB::pop_block(blk, txs);
- block_txn_stop();
+ block_wtxn_stop();
}
catch (...)
{
- block_txn_abort();
+ block_wtxn_abort();
throw;
}
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index f6b00817d..4b46f081e 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -310,11 +310,14 @@ public:
virtual void batch_stop();
virtual void batch_abort();
- virtual void block_txn_start(bool readonly);
- virtual void block_txn_stop();
- virtual void block_txn_abort();
- virtual bool block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) const;
+ virtual void block_wtxn_start();
+ virtual void block_wtxn_stop();
+ virtual void block_wtxn_abort();
+ virtual bool block_rtxn_start() const;
virtual void block_rtxn_stop() const;
+ virtual void block_rtxn_abort() const;
+
+ bool block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) const;
virtual void pop_block(block& blk, std::vector<transaction>& txs);
diff --git a/src/blockchain_db/testdb.h b/src/blockchain_db/testdb.h
index 04fad26a4..1492fb2ae 100644
--- a/src/blockchain_db/testdb.h
+++ b/src/blockchain_db/testdb.h
@@ -55,9 +55,13 @@ public:
virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) { return true; }
virtual void batch_stop() {}
virtual void set_batch_transactions(bool) {}
- virtual void block_txn_start(bool readonly=false) {}
- virtual void block_txn_stop() {}
- virtual void block_txn_abort() {}
+ virtual void block_wtxn_start() {}
+ virtual void block_wtxn_stop() {}
+ virtual void block_wtxn_abort() {}
+ virtual bool block_rtxn_start() const { return true; }
+ virtual void block_rtxn_stop() const {}
+ virtual void block_rtxn_abort() const {}
+
virtual void drop_hard_fork_info() {}
virtual bool block_exists(const crypto::hash& h, uint64_t *height) const { return false; }
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); }
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 8454595ac..cb9154f29 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -194,7 +194,11 @@ int check_flush(cryptonote::core &core, std::vector<block_complete_entry> &block
core.prevalidate_block_hashes(core.get_blockchain_storage().get_db().height(), hashes);
std::vector<block> pblocks;
- core.prepare_handle_incoming_blocks(blocks, pblocks);
+ if (!core.prepare_handle_incoming_blocks(blocks, pblocks))
+ {
+ MERROR("Failed to prepare to add blocks");
+ return 1;
+ }
if (!pblocks.empty() && pblocks.size() != blocks.size())
{
MERROR("Unexpected parsed blocks size");
diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
index 89bca2f09..d5710f727 100644
--- a/src/cryptonote_basic/hardfork.cpp
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -185,26 +185,8 @@ void HardFork::init()
else
height = 1;
- bool populate = false;
- try
- {
- db.get_hard_fork_version(0);
- }
- catch (...) { populate = true; }
- if (populate) {
- MINFO("The DB has no hard fork info, reparsing from start");
- height = 1;
- }
- MDEBUG("reorganizing from " << height);
- if (populate) {
- reorganize_from_chain_height(height);
- // reorg will not touch the genesis block, use this as a flag for populating done
- db.set_hard_fork_version(0, original_version);
- }
- else {
- rescan_from_chain_height(height);
- }
- MDEBUG("reorganization done");
+ rescan_from_chain_height(height);
+ MDEBUG("init done");
}
uint8_t HardFork::get_block_version(uint64_t height) const
@@ -266,11 +248,9 @@ bool HardFork::reorganize_from_chain_height(uint64_t height)
bool HardFork::rescan_from_block_height(uint64_t height)
{
CRITICAL_REGION_LOCAL(lock);
- db.block_txn_start(true);
- if (height >= db.height()) {
- db.block_txn_stop();
+ db_rtxn_guard rtxn_guard(&db);
+ if (height >= db.height())
return false;
- }
versions.clear();
@@ -293,8 +273,6 @@ bool HardFork::rescan_from_block_height(uint64_t height)
current_fork_index = voted;
}
- db.block_txn_stop();
-
return true;
}
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index e6c6bddb6..173679e21 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -528,6 +528,7 @@ namespace cryptonote
uint32_t local_template_ver = 0;
block b;
slow_hash_allocate_state();
+ ++m_threads_active;
while(!m_stop)
{
if(m_pausers_count)//anti split workaround
diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt
index fb96de226..2cbe89b01 100644
--- a/src/cryptonote_core/CMakeLists.txt
+++ b/src/cryptonote_core/CMakeLists.txt
@@ -30,6 +30,7 @@ set(cryptonote_core_sources
blockchain.cpp
cryptonote_core.cpp
tx_pool.cpp
+ tx_sanity_check.cpp
cryptonote_tx_utils.cpp)
set(cryptonote_core_headers)
@@ -39,6 +40,7 @@ set(cryptonote_core_private_headers
blockchain.h
cryptonote_core.h
tx_pool.h
+ tx_sanity_check.h
cryptonote_tx_utils.h)
monero_private_headers(cryptonote_core
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 7ef8f8c45..f733efb2f 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -428,6 +428,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
block bl;
block_verification_context bvc = boost::value_initialized<block_verification_context>();
generate_genesis_block(bl, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE);
+ db_wtxn_guard wtxn_guard(m_db);
add_new_block(bl, bvc);
CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "Failed to add genesis block to blockchain");
}
@@ -443,7 +444,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
m_db->fixup();
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
+
// check how far behind we are
uint64_t top_block_timestamp = m_db->get_top_block_timestamp();
uint64_t timestamp_diff = time(NULL) - top_block_timestamp;
@@ -464,7 +466,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
#endif
MINFO("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block());
- m_db->block_txn_stop();
+
+ rtxn_guard.stop();
uint64_t num_popped_blocks = 0;
while (!m_db->is_read_only())
@@ -518,8 +521,11 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
if (test_options && test_options->long_term_block_weight_window)
m_long_term_block_weights_window = test_options->long_term_block_weight_window;
- if (!update_next_cumulative_weight_limit())
- return false;
+ {
+ db_txn_guard txn_guard(m_db, m_db->is_read_only());
+ if (!update_next_cumulative_weight_limit())
+ return false;
+ }
return true;
}
//------------------------------------------------------------------
@@ -725,6 +731,7 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
m_db->reset();
m_hardfork->init();
+ db_wtxn_guard wtxn_guard(m_db);
block_verification_context bvc = boost::value_initialized<block_verification_context>();
add_new_block(b, bvc);
if (!update_next_cumulative_weight_limit())
@@ -772,7 +779,7 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
if(!sz)
return true;
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
bool genesis_included = false;
uint64_t current_back_offset = 1;
while(current_back_offset < sz)
@@ -799,7 +806,6 @@ bool Blockchain::get_short_chain_history(std::list<crypto::hash>& ids) const
{
ids.push_back(m_db->get_block_hash_from_height(0));
}
- m_db->block_txn_stop();
return true;
}
@@ -1866,7 +1872,7 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard (m_db);
rsp.current_blockchain_height = get_current_blockchain_height();
std::vector<std::pair<cryptonote::blobdata,block>> blocks;
get_blocks(arg.blocks, blocks, rsp.missed_ids);
@@ -1893,7 +1899,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
// as done below if any standalone transactions were requested
// and missed.
rsp.missed_ids.insert(rsp.missed_ids.end(), missed_tx_ids.begin(), missed_tx_ids.end());
- m_db->block_txn_stop();
return false;
}
@@ -1903,7 +1908,6 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
//get and pack other transactions, if needed
get_transactions_blobs(arg.txs, rsp.txs, rsp.missed_ids);
- m_db->block_txn_stop();
return true;
}
//------------------------------------------------------------------
@@ -2075,14 +2079,13 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
return false;
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
// make sure that the last block in the request's block list matches
// the genesis block
auto gen_hash = m_db->get_block_hash_from_height(0);
if(qblock_ids.back() != gen_hash)
{
MCERROR("net.p2p", "Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block mismatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection");
- m_db->block_txn_abort();
return false;
}
@@ -2100,11 +2103,9 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
catch (const std::exception& e)
{
MWARNING("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it);
- m_db->block_txn_abort();
return false;
}
}
- m_db->block_txn_stop();
// this should be impossible, as we checked that we share the genesis block,
// but just in case...
@@ -2284,7 +2285,7 @@ bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container
// Find the split point between us and foreign blockchain and return
// (by reference) the most recent common block hash along with up to
// BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.
-bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height) const
+bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height, bool clip_pruned) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2295,11 +2296,15 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
return false;
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
current_height = get_current_blockchain_height();
- const uint32_t pruning_seed = get_blockchain_pruning_seed();
- start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed);
- uint64_t stop_height = tools::get_next_pruned_block_height(start_height, current_height, pruning_seed);
+ uint64_t stop_height = current_height;
+ if (clip_pruned)
+ {
+ const uint32_t pruning_seed = get_blockchain_pruning_seed();
+ start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed);
+ stop_height = tools::get_next_pruned_block_height(start_height, current_height, pruning_seed);
+ }
size_t count = 0;
hashes.reserve(std::min((size_t)(stop_height - start_height), (size_t)BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT));
for(size_t i = start_height; i < stop_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
@@ -2307,7 +2312,6 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
hashes.push_back(m_db->get_block_hash_from_height(i));
}
- m_db->block_txn_stop();
return true;
}
@@ -2316,7 +2320,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
- bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height);
+ bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height, true);
if (result)
{
cryptonote::difficulty_type wide_cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1);
@@ -2354,7 +2358,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
}
}
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
total_height = get_current_blockchain_height();
size_t count = 0, size = 0;
blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height)));
@@ -2380,7 +2384,6 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
blocks.back().second.push_back(std::make_pair(b.tx_hashes[i], std::move(txs[i])));
}
}
- m_db->block_txn_stop();
return true;
}
//------------------------------------------------------------------
@@ -3535,7 +3538,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
static bool seen_future_version = false;
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
uint64_t blockchain_height;
const crypto::hash top_hash = get_tail_id(blockchain_height);
++blockchain_height; // block height to chain height
@@ -3544,7 +3547,6 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
MERROR_VER("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << top_hash);
bvc.m_verifivation_failed = true;
leave:
- m_db->block_txn_stop();
return false;
}
@@ -3827,7 +3829,7 @@ leave:
if(precomputed)
block_processing_time += m_fake_pow_calc_time;
- m_db->block_txn_stop();
+ rtxn_guard.stop();
TIME_MEASURE_START(addblock);
uint64_t new_height = 0;
if (!bvc.m_verifivation_failed)
@@ -3896,6 +3898,10 @@ leave:
//------------------------------------------------------------------
bool Blockchain::prune_blockchain(uint32_t pruning_seed)
{
+ m_tx_pool.lock();
+ epee::misc_utils::auto_scope_leave_caller unlocker = epee::misc_utils::create_scope_leave_handler([&](){m_tx_pool.unlock();});
+ CRITICAL_REGION_LOCAL(m_blockchain_lock);
+
return m_db->prune_blockchain(pruning_seed);
}
//------------------------------------------------------------------
@@ -3945,8 +3951,6 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
LOG_PRINT_L3("Blockchain::" << __func__);
- m_db->block_txn_start(false);
-
// when we reach this, the last hf version is not yet written to the db
const uint64_t db_height = m_db->height();
const uint8_t hf_version = get_current_hard_fork_version();
@@ -3990,7 +3994,6 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
new_weights[0] = long_term_block_weight;
long_term_median = epee::misc_utils::median(new_weights);
m_long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
- short_term_constraint = m_long_term_effective_median_block_weight + m_long_term_effective_median_block_weight * 2 / 5;
weights.clear();
get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW);
@@ -4009,9 +4012,8 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
if (long_term_effective_median_block_weight)
*long_term_effective_median_block_weight = m_long_term_effective_median_block_weight;
- m_db->add_max_block_size(m_current_block_cumul_weight_limit);
-
- m_db->block_txn_stop();
+ if (!m_db->is_read_only())
+ m_db->add_max_block_size(m_current_block_cumul_weight_limit);
return true;
}
@@ -4022,12 +4024,11 @@ bool Blockchain::add_new_block(const block& bl, block_verification_context& bvc)
crypto::hash id = get_block_hash(bl);
CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process
CRITICAL_REGION_LOCAL1(m_blockchain_lock);
- m_db->block_txn_start(true);
+ db_rtxn_guard rtxn_guard(m_db);
if(have_block(id))
{
LOG_PRINT_L3("block with id = " << id << " already exists");
bvc.m_already_exists = true;
- m_db->block_txn_stop();
m_blocks_txs_check.clear();
return false;
}
@@ -4037,14 +4038,14 @@ bool Blockchain::add_new_block(const block& bl, block_verification_context& bvc)
{
//chain switching or wrong block
bvc.m_added_to_main_chain = false;
- m_db->block_txn_stop();
+ rtxn_guard.stop();
bool r = handle_alternative_block(bl, id, bvc);
m_blocks_txs_check.clear();
return r;
//never relay alternative blocks
}
- m_db->block_txn_stop();
+ rtxn_guard.stop();
return handle_block_to_main_chain(bl, id, bvc);
}
//------------------------------------------------------------------
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 3588bbd1b..244e2a89a 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -394,10 +394,11 @@ namespace cryptonote
* @param hashes the hashes to be returned, return-by-reference
* @param start_height the start height, return-by-reference
* @param current_height the current blockchain height, return-by-reference
+ * @param clip_pruned whether to constrain results to unpruned data
*
* @return true if a block found in common, else false
*/
- bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height) const;
+ bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, uint64_t& start_height, uint64_t& current_height, bool clip_pruned) const;
/**
* @brief get recent block hashes for a foreign chain
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 91dea4982..be1ea5a17 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1609,6 +1609,9 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::check_fork_time()
{
+ if (m_nettype == FAKECHAIN)
+ return true;
+
HardFork::State state = m_blockchain_storage.get_hard_fork_state();
const el::Level level = el::Level::Warning;
switch (state) {
@@ -1824,7 +1827,7 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::check_block_rate()
{
- if (m_offline || m_target_blockchain_height > get_current_blockchain_height())
+ if (m_offline || m_nettype == FAKECHAIN || m_target_blockchain_height > get_current_blockchain_height())
{
MDEBUG("Not checking block rate, offline or syncing");
return true;
diff --git a/src/cryptonote_core/tx_sanity_check.cpp b/src/cryptonote_core/tx_sanity_check.cpp
new file mode 100644
index 000000000..d3b225f1c
--- /dev/null
+++ b/src/cryptonote_core/tx_sanity_check.cpp
@@ -0,0 +1,100 @@
+// Copyright (c) 2019, 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 <stdint.h>
+#include <vector>
+#include "cryptonote_basic/cryptonote_basic_impl.h"
+#include "cryptonote_basic/cryptonote_format_utils.h"
+#include "blockchain.h"
+#include "tx_sanity_check.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "txsanity"
+
+namespace cryptonote
+{
+
+bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob)
+{
+ cryptonote::transaction tx;
+
+ if (!cryptonote::parse_and_validate_tx_from_blob(tx_blob, tx))
+ {
+ MERROR("Failed to parse transaction");
+ return false;
+ }
+
+ if (cryptonote::is_coinbase(tx))
+ {
+ MERROR("Transaction is coinbase");
+ return false;
+ }
+ std::set<uint64_t> rct_indices;
+ size_t n_indices = 0;
+
+ for (const auto &txin : tx.vin)
+ {
+ if (txin.type() != typeid(cryptonote::txin_to_key))
+ continue;
+ const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(txin);
+ if (in_to_key.amount != 0)
+ continue;
+ const std::vector<uint64_t> absolute = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
+ for (uint64_t offset: absolute)
+ rct_indices.insert(offset);
+ n_indices += in_to_key.key_offsets.size();
+ }
+
+ if (n_indices <= 10)
+ {
+ MERROR("n_indices is only " << n_indices);
+ return true;
+ }
+
+ uint64_t n_available = blockchain.get_num_mature_outputs(0);
+ if (n_available < 10000)
+ return true;
+
+ if (rct_indices.size() < n_indices * 9 / 10)
+ {
+ MERROR("unique indices is only " << rct_indices.size() << "/" << n_indices);
+ return false;
+ }
+
+ std::vector<uint64_t> offsets(rct_indices.begin(), rct_indices.end());
+ uint64_t median = epee::misc_utils::median(offsets);
+ if (median < n_available * 9 / 10)
+ {
+ MERROR("median is " << median << "/" << n_available);
+ return false;
+ }
+
+ return true;
+}
+
+}
diff --git a/src/cryptonote_core/tx_sanity_check.h b/src/cryptonote_core/tx_sanity_check.h
new file mode 100644
index 000000000..c12d1b0b1
--- /dev/null
+++ b/src/cryptonote_core/tx_sanity_check.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2019, 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 "cryptonote_basic/blobdatatype.h"
+
+namespace cryptonote
+{
+ class Blockchain;
+
+ bool tx_sanity_check(Blockchain &blockchain, const cryptonote::blobdata &tx_blob);
+}
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index b7a50783a..7adca3158 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -2366,6 +2366,8 @@ skip:
{
MINFO("Target height decreasing from " << previous_target << " to " << target);
m_core.set_target_blockchain_height(target);
+ if (target == 0 && context.m_state > cryptonote_connection_context::state_before_handshake && !m_stopping)
+ MCWARNING("global", "monerod is now disconnected from the network");
}
m_block_queue.flush_spans(context.m_connection_id, false);
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index c3ac24b70..9e1c86b91 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -257,7 +257,12 @@ int main(int argc, char const * argv[])
bf::path log_file_path {data_dir / std::string(CRYPTONOTE_NAME ".log")};
if (!command_line::is_arg_defaulted(vm, daemon_args::arg_log_file))
log_file_path = command_line::get_arg(vm, daemon_args::arg_log_file);
- log_file_path = bf::absolute(log_file_path, relative_path_base);
+#ifdef __WIN32
+ if (!strchr(log_file_path.c_str(), '/') && !strchr(log_file_path.c_str(), '\\'))
+#else
+ if (!strchr(log_file_path.c_str(), '/'))
+#endif
+ log_file_path = bf::absolute(log_file_path, relative_path_base);
mlog_configure(log_file_path.string(), true, command_line::get_arg(vm, daemon_args::arg_max_log_file_size), command_line::get_arg(vm, daemon_args::arg_max_log_files));
// Set log level
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 5901be662..186296dc9 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -553,7 +553,7 @@ bool t_rpc_command_executor::mining_status() {
if (!mining_busy && mres.active && mres.speed > 0 && mres.block_target > 0 && mres.difficulty > 0)
{
- double ratio = mres.speed * mres.block_target / mres.difficulty;
+ double ratio = mres.speed * mres.block_target / (double)mres.difficulty;
uint64_t daily = 86400ull / mres.block_target * mres.block_reward * ratio;
uint64_t monthly = 86400ull / mres.block_target * 30.5 * mres.block_reward * ratio;
uint64_t yearly = 86400ull / mres.block_target * 356 * mres.block_reward * ratio;
@@ -2205,7 +2205,7 @@ bool t_rpc_command_executor::prune_blockchain()
}
}
- tools::success_msg_writer() << "Blockchain pruned: seed " << epee::string_tools::to_string_hex(res.pruning_seed);
+ tools::success_msg_writer() << "Blockchain pruned";
return true;
}
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 7d13b3216..be97edbe5 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -176,8 +176,15 @@ namespace nodetool
if(!addr.is_blockable())
return false;
+ const time_t now = time(nullptr);
+
CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
- m_blocked_hosts[addr.host_str()] = time(nullptr) + seconds;
+ time_t limit;
+ if (now > std::numeric_limits<time_t>::max() - seconds)
+ limit = std::numeric_limits<time_t>::max();
+ else
+ limit = now + seconds;
+ m_blocked_hosts[addr.host_str()] = limit;
// drop any connection to that address. This should only have to look into
// the zone related to the connection, but really make sure everything is
diff --git a/src/ringct/bulletproofs.cc b/src/ringct/bulletproofs.cc
index e394ef088..6270d4d14 100644
--- a/src/ringct/bulletproofs.cc
+++ b/src/ringct/bulletproofs.cc
@@ -48,12 +48,12 @@ extern "C"
//#define DEBUG_BP
-#if 1
+#if 0
#define PERF_TIMER_START_BP(x) PERF_TIMER_START_UNIT(x, 1000000)
#define PERF_TIMER_STOP_BP(x) PERF_TIMER_STOP(x)
#else
-#define PERF_TIMER_START_BP(x) ((void*)0)
-#define PERF_TIMER_STOP_BP(x) ((void*)0)
+#define PERF_TIMER_START_BP(x) ((void)0)
+#define PERF_TIMER_STOP_BP(x) ((void)0)
#endif
#define STRAUS_SIZE_LIMIT 232
@@ -439,35 +439,35 @@ static epee::span<const rct::key> slice(const rct::keyV &a, size_t start, size_t
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1)
{
- rct::keyV data;
- data.reserve(3);
- data.push_back(hash_cache);
- data.push_back(mash0);
- data.push_back(mash1);
- return hash_cache = rct::hash_to_scalar(data);
+ rct::key data[3];
+ data[0] = hash_cache;
+ data[1] = mash0;
+ data[2] = mash1;
+ rct::hash_to_scalar(hash_cache, data, sizeof(data));
+ return hash_cache;
}
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2)
{
- rct::keyV data;
- data.reserve(4);
- data.push_back(hash_cache);
- data.push_back(mash0);
- data.push_back(mash1);
- data.push_back(mash2);
- return hash_cache = rct::hash_to_scalar(data);
+ rct::key data[4];
+ data[0] = hash_cache;
+ data[1] = mash0;
+ data[2] = mash1;
+ data[3] = mash2;
+ rct::hash_to_scalar(hash_cache, data, sizeof(data));
+ return hash_cache;
}
static rct::key hash_cache_mash(rct::key &hash_cache, const rct::key &mash0, const rct::key &mash1, const rct::key &mash2, const rct::key &mash3)
{
- rct::keyV data;
- data.reserve(5);
- data.push_back(hash_cache);
- data.push_back(mash0);
- data.push_back(mash1);
- data.push_back(mash2);
- data.push_back(mash3);
- return hash_cache = rct::hash_to_scalar(data);
+ rct::key data[5];
+ data[0] = hash_cache;
+ data[1] = mash0;
+ data[2] = mash1;
+ data[3] = mash2;
+ data[4] = mash3;
+ rct::hash_to_scalar(hash_cache, data, sizeof(data));
+ return hash_cache;
}
/* Given a value v (0..2^N-1) and a mask gamma, construct a range proof */
@@ -825,6 +825,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
size_t inv_offset = 0;
std::vector<rct::key> to_invert;
to_invert.reserve(11 * sizeof(proofs));
+ size_t max_logM = 0;
for (const Bulletproof *p: proofs)
{
const Bulletproof &proof = *p;
@@ -861,6 +862,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
size_t M;
for (pd.logM = 0; (M = 1<<pd.logM) <= maxM && M < proof.V.size(); ++pd.logM);
CHECK_AND_ASSERT_MES(proof.L.size() == 6+pd.logM, false, "Proof is not the expected size");
+ max_logM = std::max(pd.logM, max_logM);
const size_t rounds = pd.logM+logN;
CHECK_AND_ASSERT_MES(rounds > 0, false, "Zero rounds");
@@ -888,7 +890,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
rct::key tmp;
std::vector<MultiexpData> multiexp_data;
- multiexp_data.reserve(nV + (2 * (10/*logM*/ + logN) + 4) * proofs.size() + 2 * maxMN);
+ multiexp_data.reserve(nV + (2 * (max_logM + logN) + 4) * proofs.size() + 2 * maxMN);
multiexp_data.resize(2 * maxMN);
PERF_TIMER_START_BP(VERIFY_line_24_25_invert);
@@ -901,6 +903,8 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
rct::keyV m_z4(maxMN, rct::zero()), m_z5(maxMN, rct::zero());
rct::key m_y0 = rct::zero(), y1 = rct::zero();
int proof_data_index = 0;
+ rct::keyV w_cache;
+ rct::keyV proof8_V, proof8_L, proof8_R;
for (const Bulletproof *p: proofs)
{
const Bulletproof &proof = *p;
@@ -913,9 +917,9 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
const rct::key weight_z = rct::skGen();
// pre-multiply some points by 8
- rct::keyV proof8_V = proof.V; for (rct::key &k: proof8_V) k = rct::scalarmult8(k);
- rct::keyV proof8_L = proof.L; for (rct::key &k: proof8_L) k = rct::scalarmult8(k);
- rct::keyV proof8_R = proof.R; for (rct::key &k: proof8_R) k = rct::scalarmult8(k);
+ proof8_V.resize(proof.V.size()); for (size_t i = 0; i < proof.V.size(); ++i) proof8_V[i] = rct::scalarmult8(proof.V[i]);
+ proof8_L.resize(proof.L.size()); for (size_t i = 0; i < proof.L.size(); ++i) proof8_L[i] = rct::scalarmult8(proof.L[i]);
+ proof8_R.resize(proof.R.size()); for (size_t i = 0; i < proof.R.size(); ++i) proof8_R[i] = rct::scalarmult8(proof.R[i]);
rct::key proof8_T1 = rct::scalarmult8(proof.T1);
rct::key proof8_T2 = rct::scalarmult8(proof.T2);
rct::key proof8_S = rct::scalarmult8(proof.S);
@@ -976,7 +980,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
// precalc
PERF_TIMER_START_BP(VERIFY_line_24_25_precalc);
- rct::keyV w_cache(1<<rounds);
+ w_cache.resize(1<<rounds);
w_cache[0] = winv[0];
w_cache[1] = pd.w[0];
for (size_t j = 1; j < rounds; ++j)
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index e877c13ce..ff2a81d43 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -695,6 +695,7 @@ namespace rct {
CHECK_AND_ASSERT_THROW_MES(mixRing[n].size() == inSk.size(), "Bad mixRing size");
}
CHECK_AND_ASSERT_THROW_MES((kLRki && msout) || (!kLRki && !msout), "Only one of kLRki/msout is present");
+ CHECK_AND_ASSERT_THROW_MES(inSk.size() < 2, "genRct is not suitable for 2+ rings");
rctSig rv;
rv.type = RCTTypeFull;
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 50d0f4d91..e5413f1dc 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -191,6 +191,8 @@ namespace rct {
Bulletproof(const rct::keyV &V, const rct::key &A, const rct::key &S, const rct::key &T1, const rct::key &T2, const rct::key &taux, const rct::key &mu, const rct::keyV &L, const rct::keyV &R, const rct::key &a, const rct::key &b, const rct::key &t):
V(V), A(A), S(S), T1(T1), T2(T2), taux(taux), mu(mu), L(L), R(R), a(a), b(b), t(t) {}
+ bool operator==(const Bulletproof &other) const { return V == other.V && A == other.A && S == other.S && T1 == other.T1 && T2 == other.T2 && taux == other.taux && mu == other.mu && L == other.L && R == other.R && a == other.a && b == other.b && t == other.t; }
+
BEGIN_SERIALIZE_OBJECT()
// Commitments aren't saved, they're restored via outPk
// FIELD(V)
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index d3142345c..c41fb37d8 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -41,6 +41,7 @@ using namespace epee;
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
+#include "cryptonote_core/tx_sanity_check.h"
#include "misc_language.h"
#include "net/parse.h"
#include "storages/http_abstract_invoke.h"
@@ -432,17 +433,12 @@ namespace cryptonote
if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_HASHES_FAST>(invoke_http_mode::BIN, "/gethashes.bin", req, res, r))
return r;
- NOTIFY_RESPONSE_CHAIN_ENTRY::request resp;
-
- resp.start_height = req.start_height;
- if(!m_core.find_blockchain_supplement(req.block_ids, resp))
+ res.start_height = req.start_height;
+ if(!m_core.get_blockchain_storage().find_blockchain_supplement(req.block_ids, res.m_block_ids, res.start_height, res.current_height, false))
{
res.status = "Failed";
return false;
}
- res.current_height = resp.total_height;
- res.start_height = resp.start_height;
- res.m_block_ids = std::move(resp.m_block_ids);
res.status = CORE_RPC_STATUS_OK;
return true;
@@ -574,7 +570,7 @@ namespace cryptonote
// try the pool for any missing txes
size_t found_in_pool = 0;
std::unordered_set<crypto::hash> pool_tx_hashes;
- std::unordered_map<crypto::hash, bool> double_spend_seen;
+ std::unordered_map<crypto::hash, tx_info> per_tx_pool_tx_info;
if (!missed_txs.empty())
{
std::vector<tx_info> pool_tx_info;
@@ -629,7 +625,7 @@ namespace cryptonote
{
if (ti.id_hash == hash_string)
{
- double_spend_seen.insert(std::make_pair(h, ti.double_spend_seen));
+ per_tx_pool_tx_info.insert(std::make_pair(h, ti));
break;
}
}
@@ -715,14 +711,17 @@ namespace cryptonote
if (e.in_pool)
{
e.block_height = e.block_timestamp = std::numeric_limits<uint64_t>::max();
- if (double_spend_seen.find(tx_hash) != double_spend_seen.end())
+ auto it = per_tx_pool_tx_info.find(tx_hash);
+ if (it != per_tx_pool_tx_info.end())
{
- e.double_spend_seen = double_spend_seen[tx_hash];
+ e.double_spend_seen = it->second.double_spend_seen;
+ e.relayed = it->second.relayed;
}
else
{
- MERROR("Failed to determine double spend status for " << tx_hash);
+ MERROR("Failed to determine pool info for " << tx_hash);
e.double_spend_seen = false;
+ e.relayed = false;
}
}
else
@@ -730,6 +729,7 @@ namespace cryptonote
e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash);
e.block_timestamp = m_core.get_blockchain_storage().get_db().get_block_timestamp(e.block_height);
e.double_spend_seen = false;
+ e.relayed = false;
}
// fill up old style responses too, in case an old wallet asks
@@ -845,6 +845,14 @@ namespace cryptonote
return true;
}
+ if (req.do_sanity_checks && !cryptonote::tx_sanity_check(m_core.get_blockchain_storage(), tx_blob))
+ {
+ res.status = "Failed";
+ res.reason = "Sanity check failed";
+ res.sanity_check_failed = true;
+ return true;
+ }
+
cryptonote_connection_context fake_context = AUTO_VAL_INIT(fake_context);
tx_verification_context tvc = AUTO_VAL_INIT(tvc);
if(!m_core.handle_incoming_tx(tx_blob, tvc, false, false, req.do_not_relay) || tvc.m_verifivation_failed)
@@ -1296,7 +1304,10 @@ namespace cryptonote
LOG_ERROR("Failed to find tx pub key in blockblob");
return false;
}
- res.reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
+ if (req.reserve_size)
+ res.reserved_offset += sizeof(tx_pub_key) + 2; //2 bytes: tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
+ else
+ res.reserved_offset = 0;
if(res.reserved_offset + req.reserve_size > block_blob.size())
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -1394,11 +1405,9 @@ namespace cryptonote
submit_req.push_back(boost::value_initialized<std::string>());
res.height = m_core.get_blockchain_storage().get_current_blockchain_height();
- bool r = CORE_RPC_STATUS_OK;
-
for(size_t i = 0; i < req.amount_of_blocks; i++)
{
- r = on_getblocktemplate(template_req, template_res, error_resp, ctx);
+ bool r = on_getblocktemplate(template_req, template_res, error_resp, ctx);
res.status = template_res.status;
template_req.prev_block.clear();
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index a42ca2494..e4683bbe2 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -40,6 +40,9 @@
#include "p2p/net_node.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "daemon.rpc"
+
// yes, epee doesn't properly use its full namespace when calling its
// functions from macros. *sigh*
using namespace epee;
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 70a5a475a..cfe4bbf23 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -364,6 +364,7 @@ namespace cryptonote
uint64_t block_height;
uint64_t block_timestamp;
std::vector<uint64_t> output_indices;
+ bool relayed;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
@@ -374,9 +375,16 @@ namespace cryptonote
KV_SERIALIZE(as_json)
KV_SERIALIZE(in_pool)
KV_SERIALIZE(double_spend_seen)
- KV_SERIALIZE(block_height)
- KV_SERIALIZE(block_timestamp)
- KV_SERIALIZE(output_indices)
+ if (!this_ref.in_pool)
+ {
+ KV_SERIALIZE(block_height)
+ KV_SERIALIZE(block_timestamp)
+ KV_SERIALIZE(output_indices)
+ }
+ else
+ {
+ KV_SERIALIZE(relayed)
+ }
END_KV_SERIALIZE_MAP()
};
@@ -577,10 +585,12 @@ namespace cryptonote
{
std::string tx_as_hex;
bool do_not_relay;
+ bool do_sanity_checks;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_as_hex)
KV_SERIALIZE_OPT(do_not_relay, false)
+ KV_SERIALIZE_OPT(do_sanity_checks, true)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -599,6 +609,7 @@ namespace cryptonote
bool overspend;
bool fee_too_low;
bool not_rct;
+ bool sanity_check_failed;
bool untrusted;
BEGIN_KV_SERIALIZE_MAP()
@@ -613,6 +624,7 @@ namespace cryptonote
KV_SERIALIZE(overspend)
KV_SERIALIZE(fee_too_low)
KV_SERIALIZE(not_rct)
+ KV_SERIALIZE(sanity_check_failed)
KV_SERIALIZE(untrusted)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index 540afe6b9..7c8953930 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -141,7 +141,7 @@ namespace rpc
auto& chain = m_core.get_blockchain_storage();
- if (!chain.find_blockchain_supplement(req.known_hashes, res.hashes, res.start_height, res.current_height))
+ if (!chain.find_blockchain_supplement(req.known_hashes, res.hashes, res.start_height, res.current_height, false))
{
res.status = Message::STATUS_FAILED;
res.error_details = "Blockchain::find_blockchain_supplement() returned false";
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 2e134931f..560c5be24 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -118,7 +118,7 @@ typedef cryptonote::simple_wallet sw;
if (!m_long_payment_id_support) { \
fail_msg_writer() << tr("Warning: Long payment IDs are obsolete."); \
fail_msg_writer() << tr("Long payment IDs are not encrypted on the blockchain, and will harm your privacy."); \
- fail_msg_writer() << tr("Use --long-payment-id-support if you really must use one, and warn the recipient they are using an obsolete feature that will disappear in the future."); \
+ fail_msg_writer() << tr("Use --long-payment-id-support-bad-for-privacy if you really must use one, and warn the recipient they are using an obsolete feature that will disappear in the future."); \
return true; \
} \
} while(0)
@@ -4092,6 +4092,14 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (welcome)
message_writer(console_color_yellow, true) << tr("If you are new to Monero, type \"welcome\" for a brief overview.");
+ if (m_long_payment_id_support)
+ {
+ message_writer(console_color_red, false) <<
+ tr("WARNING: obsolete long payment IDs are enabled. Sending transactions with those payment IDs are bad for your privacy.");
+ message_writer(console_color_red, false) <<
+ tr("It is recommended that you do not use them, and ask recipients who ask for one to not endanger your privacy.");
+ }
+
return true;
}
//----------------------------------------------------------------------------------------------------
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index f5f3c0e1b..1d5078a11 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -37,9 +37,10 @@ namespace tools
static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
-NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex)
+NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::recursive_mutex &mutex)
: m_http_client(http_client)
, m_daemon_rpc_mutex(mutex)
+ , m_offline(false)
{
invalidate();
}
@@ -61,6 +62,8 @@ void NodeRPCProxy::invalidate()
boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const
{
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_rpc_version == 0)
{
cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
@@ -84,6 +87,8 @@ void NodeRPCProxy::set_height(uint64_t h)
boost::optional<std::string> NodeRPCProxy::get_info() const
{
+ if (m_offline)
+ return boost::optional<std::string>("offline");
const time_t now = time(NULL);
if (now >= m_get_info_time + 30) // re-cache every 30 seconds
{
@@ -134,6 +139,8 @@ boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &bloc
boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const
{
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_earliest_height[version] == 0)
{
cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req_t = AUTO_VAL_INIT(req_t);
@@ -161,6 +168,8 @@ boost::optional<std::string> NodeRPCProxy::get_dynamic_base_fee_estimate(uint64_
if (result)
return result;
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_dynamic_base_fee_estimate_cached_height != height || m_dynamic_base_fee_estimate_grace_blocks != grace_blocks)
{
cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t);
@@ -191,6 +200,8 @@ boost::optional<std::string> NodeRPCProxy::get_fee_quantization_mask(uint64_t &f
if (result)
return result;
+ if (m_offline)
+ return boost::optional<std::string>("offline");
if (m_dynamic_base_fee_estimate_cached_height != height)
{
cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t);
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 3630aec08..3b75c8b94 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -39,9 +39,10 @@ namespace tools
class NodeRPCProxy
{
public:
- NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex);
+ NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::recursive_mutex &mutex);
void invalidate();
+ void set_offline(bool offline) { m_offline = offline; }
boost::optional<std::string> get_rpc_version(uint32_t &version) const;
boost::optional<std::string> get_height(uint64_t &height) const;
@@ -56,7 +57,8 @@ private:
boost::optional<std::string> get_info() const;
epee::net_utils::http::http_simple_client &m_http_client;
- boost::mutex &m_daemon_rpc_mutex;
+ boost::recursive_mutex &m_daemon_rpc_mutex;
+ bool m_offline;
mutable uint64_t m_height;
mutable uint64_t m_earliest_height[256];
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index b288994a5..a7da9395c 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -266,6 +266,7 @@ struct options {
const command_line::arg_descriptor<std::string> hw_device_derivation_path = {"hw-device-deriv-path", tools::wallet2::tr("HW device wallet derivation path (e.g., SLIP-10)"), ""};
const command_line::arg_descriptor<std::string> tx_notify = { "tx-notify" , "Run a program for each new incoming transaction, '%s' will be replaced by the transaction hash" , "" };
const command_line::arg_descriptor<bool> no_dns = {"no-dns", tools::wallet2::tr("Do not use DNS"), false};
+ const command_line::arg_descriptor<bool> offline = {"offline", tools::wallet2::tr("Do not connect to a daemon, nor use DNS"), false};
};
void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string &mms_file)
@@ -456,6 +457,9 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
if (command_line::get_arg(vm, opts.no_dns))
wallet->enable_dns(false);
+ if (command_line::get_arg(vm, opts.offline))
+ wallet->set_offline();
+
try
{
if (!command_line::is_arg_defaulted(vm, opts.tx_notify))
@@ -792,7 +796,7 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
// pseudoOuts
size += 32 * n_inputs;
// ecdhInfo
- size += 2 * 32 * n_outputs;
+ size += 8 * n_outputs;
// outPk - only commitment is saved
size += 32 * n_outputs;
// txnFee
@@ -1083,7 +1087,8 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_unattended(unattended),
m_devices_registered(false),
m_device_last_key_image_sync(0),
- m_use_dns(true)
+ m_use_dns(true),
+ m_offline(false)
{
}
@@ -1139,6 +1144,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
command_line::add_arg(desc_params, opts.hw_device_derivation_path);
command_line::add_arg(desc_params, opts.tx_notify);
command_line::add_arg(desc_params, opts.no_dns);
+ command_line::add_arg(desc_params, opts.offline);
}
std::pair<std::unique_ptr<wallet2>, tools::password_container> wallet2::make_from_json(const boost::program_options::variables_map& vm, bool unattended, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
@@ -1184,6 +1190,8 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia
//----------------------------------------------------------------------------------------------------
bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, bool trusted_daemon, epee::net_utils::ssl_options_t ssl_options)
{
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
+
if(m_http_client.is_connected())
m_http_client.disconnect();
m_daemon_address = std::move(daemon_address);
@@ -2392,7 +2400,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
req.start_height = start_height;
req.no_miner_tx = m_refresh_type == RefreshNoCoinbase;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_bin("/getblocks.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/getblocks.bin", req, res, rpc_timeout);
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");
@@ -2414,7 +2422,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
req.start_height = start_height;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_bin("/gethashes.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/gethashes.bin", req, res, rpc_timeout);
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");
@@ -2691,7 +2699,7 @@ void wallet2::update_pool_state(bool refreshed)
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request req;
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response res;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/get_transaction_pool_hashes.bin", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_transaction_pool_hashes.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_transaction_pool_hashes.bin");
@@ -2838,7 +2846,7 @@ void wallet2::update_pool_state(bool refreshed)
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
MDEBUG("Got " << r << " and " << res.status);
if (r && res.status == CORE_RPC_STATUS_OK)
@@ -2999,6 +3007,13 @@ std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create
//----------------------------------------------------------------------------------------------------
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money, bool check_pool)
{
+ if (m_offline)
+ {
+ blocks_fetched = 0;
+ received_money = 0;
+ return;
+ }
+
if(m_light_wallet) {
// MyMonero get_address_info needs to be called occasionally to trigger wallet sync.
@@ -3258,7 +3273,7 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
req.binary = true;
req.compress = true;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_bin("/get_output_distribution.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/get_output_distribution.bin", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
if (!r)
{
@@ -5088,7 +5103,14 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
{
THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline)
+ {
+ if (version)
+ *version = 0;
+ if (ssl)
+ *ssl = false;
+ return false;
+ }
// TODO: Add light wallet version check.
if(m_light_wallet) {
@@ -5099,20 +5121,23 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
return m_light_wallet_connected;
}
- if(!m_http_client.is_connected(ssl))
{
- m_node_rpc_proxy.invalidate();
- if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
- return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
if(!m_http_client.is_connected(ssl))
- return false;
+ {
+ m_node_rpc_proxy.invalidate();
+ if (!m_http_client.connect(std::chrono::milliseconds(timeout)))
+ return false;
+ if(!m_http_client.is_connected(ssl))
+ return false;
+ }
}
if (version)
{
cryptonote::COMMAND_RPC_GET_VERSION::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_VERSION::response resp_t = AUTO_VAL_INIT(resp_t);
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t, m_http_client);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t);
if(!r) {
*version = 0;
return false;
@@ -5126,6 +5151,18 @@ bool wallet2::check_connection(uint32_t *version, bool *ssl, uint32_t timeout)
return true;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::set_offline(bool offline)
+{
+ m_offline = offline;
+ m_http_client.set_auto_connect(!offline);
+ if (offline)
+ {
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
+ if(m_http_client.is_connected())
+ m_http_client.disconnect();
+ }
+}
+//----------------------------------------------------------------------------------------------------
bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const
{
hw::device &hwdev = m_account.get_device();
@@ -5304,7 +5341,7 @@ void wallet2::trim_hashchain()
cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response res = AUTO_VAL_INIT(res);
m_daemon_rpc_mutex.lock();
req.height = m_blockchain.size() - 1;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "getblockheaderbyheight", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
if (r && res.status == CORE_RPC_STATUS_OK)
{
@@ -5660,7 +5697,7 @@ void wallet2::rescan_spent()
for (size_t n = start_offset; n < start_offset + n_outputs; ++n)
req.key_images.push_back(string_tools::pod_to_hex(m_transfers[n].m_key_image));
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout);
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");
@@ -5988,7 +6025,7 @@ void wallet2::commit_tx(pending_tx& ptx)
oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
oreq.tx = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/submit_raw_tx", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/submit_raw_tx", oreq, ores, rpc_timeout, "POST");
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
@@ -6000,9 +6037,10 @@ void wallet2::commit_tx(pending_tx& ptx)
COMMAND_RPC_SEND_RAW_TX::request req;
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
req.do_not_relay = false;
+ req.do_sanity_checks = true;
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/sendrawtransaction", req, daemon_send_resp, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/sendrawtransaction", req, daemon_send_resp, rpc_timeout);
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");
@@ -6955,7 +6993,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
m_daemon_rpc_mutex.lock();
getbh_req.start_height = m_blockchain.size() - N;
getbh_req.end_height = m_blockchain.size() - 1;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, rpc_timeout);
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");
@@ -7126,7 +7164,7 @@ bool wallet2::unset_ring(const crypto::hash &txid)
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to get transaction from daemon");
if (res.txs.empty())
@@ -7180,8 +7218,8 @@ bool wallet2::find_and_save_rings(bool force)
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txs_hashes[s]));
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -7322,7 +7360,7 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
oreq.count = light_wallet_requested_outputs_count;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_random_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_random_outs", oreq, ores, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_random_outs");
THROW_WALLET_EXCEPTION_IF(ores.amount_outs.empty() , error::wallet_internal_error, "No outputs received from light wallet node. Error: " + ores.Error);
@@ -7462,7 +7500,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
req_t.unlocked = true;
req_t.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
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");
@@ -7485,7 +7523,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
req_t.cumulative = true;
req_t.binary = true;
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout * 1000);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, rpc_timeout * 1000);
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");
@@ -7884,7 +7922,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// get the keys for those
req.get_txid = false;
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/get_outs.bin", req, daemon_resp, rpc_timeout);
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");
@@ -8596,7 +8634,7 @@ bool wallet2::light_wallet_login(bool &new_address)
// Always create account if it doesn't exist.
request.create_account = true;
m_daemon_rpc_mutex.lock();
- bool connected = epee::net_utils::invoke_http_json("/login", request, response, m_http_client, rpc_timeout, "POST");
+ bool connected = invoke_http_json("/login", request, response, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
// MyMonero doesn't send any status message. OpenMonero does.
m_light_wallet_connected = connected && (response.status.empty() || response.status == "success");
@@ -8621,7 +8659,7 @@ bool wallet2::light_wallet_import_wallet_request(tools::COMMAND_RPC_IMPORT_WALLE
oreq.address = get_account().get_public_address_str(m_nettype);
oreq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/import_wallet_request", oreq, response, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/import_wallet_request", oreq, response, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "import_wallet_request");
@@ -8647,7 +8685,7 @@ void wallet2::light_wallet_get_unspent_outs()
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_unspent_outs", oreq, ores, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_unspent_outs", oreq, ores, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_unspent_outs");
THROW_WALLET_EXCEPTION_IF(ores.status == "error", error::wallet_internal_error, ores.reason);
@@ -8792,7 +8830,7 @@ bool wallet2::light_wallet_get_address_info(tools::COMMAND_RPC_GET_ADDRESS_INFO:
request.address = get_account().get_public_address_str(m_nettype);
request.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_address_info", request, response, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_address_info", request, response, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_info");
// TODO: Validate result
@@ -8809,7 +8847,7 @@ void wallet2::light_wallet_get_address_txs()
ireq.address = get_account().get_public_address_str(m_nettype);
ireq.view_key = string_tools::pod_to_hex(get_account().get_keys().m_view_secret_key);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/get_address_txs", ireq, ires, m_http_client, rpc_timeout, "POST");
+ bool r = invoke_http_json("/get_address_txs", ireq, ires, rpc_timeout, "POST");
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_address_txs");
//OpenMonero sends status=success, Mymonero doesn't.
@@ -10113,7 +10151,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
req_t.max_count = 0;
req_t.unlocked = unlocked;
req_t.recent_cutoff = 0;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "select_available_outputs_from_histogram");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -10151,7 +10189,7 @@ uint64_t wallet2::get_num_rct_outputs()
req_t.max_count = 0;
req_t.unlocked = true;
req_t.recent_cutoff = 0;
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_num_rct_outputs");
THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram");
@@ -10276,7 +10314,7 @@ bool wallet2::get_tx_key(const crypto::hash &txid, crypto::secret_key &tx_key, s
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -10319,8 +10357,8 @@ void wallet2::set_tx_key(const crypto::hash &txid, const crypto::secret_key &tx_
COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -10369,8 +10407,8 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -10431,8 +10469,8 @@ std::string wallet2::get_spend_proof(const crypto::hash &txid, const std::string
COMMAND_RPC_GET_OUTPUTS_BIN::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
@@ -10487,8 +10525,8 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
COMMAND_RPC_GET_TRANSACTIONS::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_json("/gettransactions", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -10560,8 +10598,8 @@ bool wallet2::check_spend_proof(const crypto::hash &txid, const std::string &mes
COMMAND_RPC_GET_OUTPUTS_BIN::response res = AUTO_VAL_INIT(res);
bool r;
{
- const boost::lock_guard<boost::mutex> lock{m_daemon_rpc_mutex};
- r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, res, m_http_client, rpc_timeout);
+ const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
+ r = invoke_http_bin("/get_outs.bin", req, res, rpc_timeout);
}
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
@@ -10659,7 +10697,7 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = epee::net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -10708,7 +10746,7 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -10863,7 +10901,7 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
req.decode_as_json = false;
req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = net_utils::invoke_http_json("/gettransactions", req, res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || (res.txs.size() != 1 && res.txs_as_hex.size() != 1),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -11155,7 +11193,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
gettx_req.decode_as_json = false;
gettx_req.prune = true;
m_daemon_rpc_mutex.lock();
- bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, m_http_client);
+ bool ok = invoke_http_json("/gettransactions", gettx_req, gettx_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || gettx_res.txs.size() != proofs.size(),
error::wallet_internal_error, "Failed to get transaction from daemon");
@@ -11166,7 +11204,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
for (size_t i = 0; i < proofs.size(); ++i)
kispent_req.key_images.push_back(epee::string_tools::pod_to_hex(proofs[i].key_image));
m_daemon_rpc_mutex.lock();
- ok = epee::net_utils::invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, m_http_client, rpc_timeout);
+ ok = invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok || kispent_res.spent_status.size() != proofs.size(),
error::wallet_internal_error, "Failed to get key image spent status from daemon");
@@ -11718,7 +11756,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
{
PERF_TIMER(import_key_images_RPC);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/is_key_image_spent", req, daemon_resp, rpc_timeout);
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");
@@ -11804,7 +11842,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
PERF_TIMER_START(import_key_images_E);
m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json("/gettransactions", gettxs_req, gettxs_res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "gettransactions");
THROW_WALLET_EXCEPTION_IF(gettxs_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "gettransactions");
@@ -12032,14 +12070,15 @@ void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vect
m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx);
}
//----------------------------------------------------------------------------------------------------
-std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs() const
+std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const
{
PERF_TIMER(export_outputs);
std::vector<tools::wallet2::transfer_details> outs;
size_t offset = 0;
- while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
- ++offset;
+ if (!all)
+ while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
+ ++offset;
outs.reserve(m_transfers.size() - offset);
for (size_t n = offset; n < m_transfers.size(); ++n)
@@ -12052,13 +12091,13 @@ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export
return std::make_pair(offset, outs);
}
//----------------------------------------------------------------------------------------------------
-std::string wallet2::export_outputs_to_str() const
+std::string wallet2::export_outputs_to_str(bool all) const
{
PERF_TIMER(export_outputs_to_str);
std::stringstream oss;
boost::archive::portable_binary_oarchive ar(oss);
- const auto& outputs = export_outputs();
+ const auto& outputs = export_outputs(all);
ar << outputs;
std::string magic(OUTPUT_EXPORT_FILE_MAGIC, strlen(OUTPUT_EXPORT_FILE_MAGIC));
@@ -12739,7 +12778,7 @@ uint64_t wallet2::get_blockchain_height_by_date(uint16_t year, uint8_t month, ui
height_mid,
height_max
};
- bool r = net_utils::invoke_http_bin("/getblocks_by_height.bin", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_bin("/getblocks_by_height.bin", req, res, rpc_timeout);
if (!r || res.status != CORE_RPC_STATUS_OK)
{
std::ostringstream oss;
@@ -12809,7 +12848,7 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request req = AUTO_VAL_INIT(req);
cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response res = AUTO_VAL_INIT(res);
m_daemon_rpc_mutex.lock();
- bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, m_http_client, rpc_timeout);
+ bool r = invoke_http_json_rpc("/json_rpc", "get_txpool_backlog", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "Failed to connect to daemon");
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog");
@@ -12879,7 +12918,7 @@ uint64_t wallet2::get_segregation_fork_height() const
if (m_segregation_height > 0)
return m_segregation_height;
- if (m_use_dns)
+ if (m_use_dns && !m_offline)
{
// All four MoneroPulse domains have DNSSEC on and valid
static const std::vector<std::string> dns_urls = {
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 39380c9df..8561c42ba 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1139,8 +1139,8 @@ namespace tools
bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const;
// Import/Export wallet data
- std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs() const;
- std::string export_outputs_to_str() const;
+ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const;
+ std::string export_outputs_to_str(bool all = false) const;
size_t import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs);
size_t import_outputs_from_str(const std::string &outputs_st);
payment_container export_payments() const;
@@ -1232,19 +1232,22 @@ namespace tools
template<class t_request, class t_response>
inline bool invoke_http_json(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
{
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline) return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
return epee::net_utils::invoke_http_json(uri, req, res, m_http_client, timeout, http_method);
}
template<class t_request, class t_response>
inline bool invoke_http_bin(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET")
{
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline) return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
return epee::net_utils::invoke_http_bin(uri, req, res, m_http_client, timeout, http_method);
}
template<class t_request, class t_response>
inline bool invoke_http_json_rpc(const boost::string_ref uri, const std::string& method_name, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET", const std::string& req_id = "0")
{
- boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
+ if (m_offline) return false;
+ boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex);
return epee::net_utils::invoke_http_json_rpc(uri, method_name, req, res, m_http_client, timeout, http_method, req_id);
}
@@ -1291,6 +1294,7 @@ namespace tools
uint64_t hash_m_transfers(int64_t transfer_height, crypto::hash &hash) const;
void finish_rescan_bc_keep_key_images(uint64_t transfer_height, const crypto::hash &hash);
void enable_dns(bool enable) { m_use_dns = enable; }
+ void set_offline(bool offline = true);
private:
/*!
@@ -1422,7 +1426,7 @@ namespace tools
std::atomic<bool> m_run;
- boost::mutex m_daemon_rpc_mutex;
+ boost::recursive_mutex m_daemon_rpc_mutex;
bool m_trusted_daemon;
i_wallet2_callback* m_callback;
@@ -1474,6 +1478,7 @@ namespace tools
std::string m_device_derivation_path;
uint64_t m_device_last_key_image_sync;
bool m_use_dns;
+ bool m_offline;
// Aux transaction data from device
std::unordered_map<crypto::hash, std::string> m_tx_device;
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 71c64d3c1..2039c6742 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -1842,11 +1842,7 @@ namespace tools
{
if (req.account_index != td.m_subaddr_index.major || (!req.subaddr_indices.empty() && req.subaddr_indices.count(td.m_subaddr_index.minor) == 0))
continue;
- if (!transfers_found)
- {
- transfers_found = true;
- }
- auto txBlob = t_serializable_object_to_blob(td.m_tx);
+ transfers_found = true;
wallet_rpc::transfer_details rpc_transfers;
rpc_transfers.amount = td.amount();
rpc_transfers.spent = td.m_spent;
@@ -2581,7 +2577,7 @@ namespace tools
try
{
- res.outputs_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->export_outputs_to_str());
+ res.outputs_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->export_outputs_to_str(req.all));
}
catch (const std::exception &e)
{
@@ -3111,6 +3107,18 @@ namespace tools
er.message = "Invalid filename";
return false;
}
+ if (m_wallet && req.autosave_current)
+ {
+ try
+ {
+ m_wallet->store();
+ }
+ catch (const std::exception& e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+ }
std::string wallet_file = m_wallet_dir + "/" + req.filename;
{
po::options_description desc("dummy");
@@ -3141,18 +3149,7 @@ namespace tools
}
if (m_wallet)
- {
- try
- {
- m_wallet->store();
- }
- catch (const std::exception& e)
- {
- handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
- return false;
- }
delete m_wallet;
- }
m_wallet = wal.release();
return true;
}
@@ -3161,14 +3158,17 @@ namespace tools
{
if (!m_wallet) return not_open(er);
- try
+ if (req.autosave_current)
{
- m_wallet->store();
- }
- catch (const std::exception& e)
- {
- handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
- return false;
+ try
+ {
+ m_wallet->store();
+ }
+ catch (const std::exception& e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
}
delete m_wallet;
m_wallet = NULL;
@@ -3385,6 +3385,20 @@ namespace tools
return false;
}
+ if (m_wallet && req.autosave_current)
+ {
+ try
+ {
+ if (!wallet_file.empty())
+ m_wallet->store();
+ }
+ catch (const std::exception &e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+ }
+
try
{
if (!req.spendkey.empty())
@@ -3433,19 +3447,7 @@ namespace tools
}
if (m_wallet)
- {
- try
- {
- if (!wallet_file.empty())
- m_wallet->store();
- }
- catch (const std::exception &e)
- {
- handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
- return false;
- }
delete m_wallet;
- }
m_wallet = wal.release();
res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
return true;
@@ -3511,6 +3513,18 @@ namespace tools
return false;
}
}
+ if (m_wallet && req.autosave_current)
+ {
+ try
+ {
+ m_wallet->store();
+ }
+ catch (const std::exception &e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+ }
// process seed_offset if given
{
@@ -3621,18 +3635,7 @@ namespace tools
}
if (m_wallet)
- {
- try
- {
- m_wallet->store();
- }
- catch (const std::exception &e)
- {
- handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
- return false;
- }
delete m_wallet;
- }
m_wallet = wal.release();
res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
res.info = "Wallet has been restored successfully.";
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index bb360ae01..8757acef2 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 9
+#define WALLET_RPC_VERSION_MINOR 10
#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
@@ -1626,7 +1626,10 @@ namespace wallet_rpc
{
struct request_t
{
+ bool all;
+
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(all)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2043,10 +2046,12 @@ namespace wallet_rpc
{
std::string filename;
std::string password;
+ bool autosave_current;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(filename)
KV_SERIALIZE(password)
+ KV_SERIALIZE_OPT(autosave_current, true)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2063,7 +2068,10 @@ namespace wallet_rpc
{
struct request_t
{
+ bool autosave_current;
+
BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_OPT(autosave_current, true)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -2108,6 +2116,7 @@ namespace wallet_rpc
std::string spendkey;
std::string viewkey;
std::string password;
+ bool autosave_current;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_OPT(restore_height, (uint64_t)0)
@@ -2116,6 +2125,7 @@ namespace wallet_rpc
KV_SERIALIZE(spendkey)
KV_SERIALIZE(viewkey)
KV_SERIALIZE(password)
+ KV_SERIALIZE_OPT(autosave_current, true)
END_KV_SERIALIZE_MAP()
};
@@ -2141,6 +2151,7 @@ namespace wallet_rpc
std::string seed_offset;
std::string password;
std::string language;
+ bool autosave_current;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_OPT(restore_height, (uint64_t)0)
@@ -2149,6 +2160,7 @@ namespace wallet_rpc
KV_SERIALIZE(seed_offset)
KV_SERIALIZE(password)
KV_SERIALIZE(language)
+ KV_SERIALIZE_OPT(autosave_current, true)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
diff --git a/tests/block_weight/block_weight.py b/tests/block_weight/block_weight.py
index ba533c53c..b23da3d77 100755
--- a/tests/block_weight/block_weight.py
+++ b/tests/block_weight/block_weight.py
@@ -9,7 +9,6 @@ import math
MEDIAN_WINDOW_SMALL = 100 # number of recent blocks for median computation
MEDIAN_WINDOW_BIG = 5000
-MULTIPLIER_SMALL = 1.4 # multipliers for determining weights
MULTIPLIER_BIG = 50.0
MEDIAN_THRESHOLD = 300*1000 # initial value for median (scaled kB -> B)
lcg_seed = 0
@@ -24,9 +23,9 @@ def get_median(vec):
#temp = vec
temp = sorted(vec)
if len(temp) % 2 == 1:
- return temp[len(temp)/2]
+ return temp[len(temp)//2]
else:
- return int((temp[len(temp)/2]+temp[len(temp)/2-1])/2)
+ return int((temp[len(temp)//2]+temp[len(temp)//2-1])//2)
def LCG():
global lcg_seed
diff --git a/tests/core_tests/bulletproofs.h b/tests/core_tests/bulletproofs.h
index efc751df7..f9768a316 100644
--- a/tests/core_tests/bulletproofs.h
+++ b/tests/core_tests/bulletproofs.h
@@ -97,7 +97,7 @@ template<>
struct get_test_options<gen_bp_tx_validation_base> {
const std::pair<uint8_t, uint64_t> hard_forks[4] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(10, 73), std::make_pair(0, 0)};
const cryptonote::test_options test_options = {
- hard_forks
+ hard_forks, 0
};
};
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index f2bcb7787..797d1207b 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -643,7 +643,15 @@ public:
log_event("cryptonote::block");
cryptonote::block_verification_context bvc = AUTO_VAL_INIT(bvc);
- m_c.handle_incoming_block(t_serializable_object_to_blob(b), &b, bvc);
+ cryptonote::blobdata bd = t_serializable_object_to_blob(b);
+ std::vector<cryptonote::block> pblocks;
+ if (m_c.prepare_handle_incoming_blocks(std::vector<cryptonote::block_complete_entry>(1, {bd, {}}), pblocks))
+ {
+ m_c.handle_incoming_block(bd, &b, bvc);
+ m_c.cleanup_handle_incoming_blocks();
+ }
+ else
+ bvc.m_verifivation_failed = true;
bool r = check_block_verification_context(bvc, m_ev_index, b, m_validator);
CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed");
return r;
@@ -666,7 +674,14 @@ public:
log_event("serialized_block");
cryptonote::block_verification_context bvc = AUTO_VAL_INIT(bvc);
- m_c.handle_incoming_block(sr_block.data, NULL, bvc);
+ std::vector<cryptonote::block> pblocks;
+ if (m_c.prepare_handle_incoming_blocks(std::vector<cryptonote::block_complete_entry>(1, {sr_block.data, {}}), pblocks))
+ {
+ m_c.handle_incoming_block(sr_block.data, NULL, bvc);
+ m_c.cleanup_handle_incoming_blocks();
+ }
+ else
+ bvc.m_verifivation_failed = true;
cryptonote::block blk;
std::stringstream ss;
@@ -748,7 +763,7 @@ template<typename t_test_class>
struct get_test_options {
const std::pair<uint8_t, uint64_t> hard_forks[2];
const cryptonote::test_options test_options = {
- hard_forks
+ hard_forks, 0
};
get_test_options():hard_forks{std::make_pair((uint8_t)1, (uint64_t)0), std::make_pair((uint8_t)0, (uint64_t)0)}{}
};
@@ -776,7 +791,7 @@ inline bool do_replay_events_get_core(std::vector<test_event_entry>& events, cry
// Hardforks can be specified in events.
v_hardforks_t hardforks;
- cryptonote::test_options test_options_tmp{};
+ cryptonote::test_options test_options_tmp{nullptr, 0};
const cryptonote::test_options * test_options_ = &gto.test_options;
if (extract_hard_forks(events, hardforks)){
hardforks.push_back(std::make_pair((uint8_t)0, (uint64_t)0)); // terminator
diff --git a/tests/core_tests/multisig.h b/tests/core_tests/multisig.h
index 1e8226d26..10fe6ffe8 100644
--- a/tests/core_tests/multisig.h
+++ b/tests/core_tests/multisig.h
@@ -84,7 +84,7 @@ template<>
struct get_test_options<gen_multisig_tx_validation_base> {
const std::pair<uint8_t, uint64_t> hard_forks[3] = {std::make_pair(1, 0), std::make_pair(4, 1), std::make_pair(0, 0)};
const cryptonote::test_options test_options = {
- hard_forks
+ hard_forks, 0
};
};
diff --git a/tests/core_tests/rct.h b/tests/core_tests/rct.h
index 72460d98e..00a2bd88c 100644
--- a/tests/core_tests/rct.h
+++ b/tests/core_tests/rct.h
@@ -83,7 +83,7 @@ template<>
struct get_test_options<gen_rct_tx_validation_base> {
const std::pair<uint8_t, uint64_t> hard_forks[4] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(4, 65), std::make_pair(0, 0)};
const cryptonote::test_options test_options = {
- hard_forks
+ hard_forks, 0
};
};
diff --git a/tests/functional_tests/transfer.py b/tests/functional_tests/transfer.py
index 050277c51..bc2f5472b 100755
--- a/tests/functional_tests/transfer.py
+++ b/tests/functional_tests/transfer.py
@@ -29,6 +29,7 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import time
+import json
"""Test simple transfers
"""
@@ -43,6 +44,7 @@ class TransferTest():
self.transfer()
self.check_get_bulk_payments()
self.check_double_spend_detection()
+ self.sweep_single()
def create(self):
print 'Creating wallets'
@@ -569,6 +571,54 @@ class TransferTest():
assert tx.in_pool
assert tx.double_spend_seen
+ def sweep_single(self):
+ daemon = Daemon()
+
+ print("Sending single output")
+
+ daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 1)
+ self.wallet[0].refresh()
+ res = self.wallet[0].incoming_transfers(transfer_type = 'available')
+ for t in res.transfers:
+ assert not t.spent
+ assert len(res.transfers) > 8 # we mined a lot
+ index = 8
+ assert not res.transfers[index].spent
+ assert res.transfers[index].amount > 0
+ ki = res.transfers[index].key_image
+ amount = res.transfers[index].amount
+ daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 10) # ensure unlocked
+ self.wallet[0].refresh()
+ res = self.wallet[0].get_balance()
+ balance = res.balance
+ res = self.wallet[0].incoming_transfers(transfer_type = 'all')
+ res = self.wallet[0].sweep_single('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', key_image = ki)
+ assert len(res.tx_hash) == 64
+ tx_hash = res.tx_hash
+ daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1)
+ self.wallet[0].refresh()
+ res = self.wallet[0].get_balance()
+ new_balance = res.balance
+ res = daemon.get_transactions([tx_hash], decode_as_json = True)
+ assert len(res.txs) == 1
+ tx = res.txs[0]
+ assert tx.tx_hash == tx_hash
+ assert not tx.in_pool
+ assert len(tx.as_json) > 0
+ try:
+ j = json.loads(tx.as_json)
+ except:
+ j = None
+ assert j
+ assert new_balance == balance - amount
+ assert len(j['vin']) == 1
+ assert j['vin'][0]['key']['k_image'] == ki
+ self.wallet[0].refresh()
+ res = self.wallet[0].incoming_transfers(transfer_type = 'available')
+ assert len([t for t in res.transfers if t.key_image == ki]) == 0
+ res = self.wallet[0].incoming_transfers(transfer_type = 'unavailable')
+ assert len([t for t in res.transfers if t.key_image == ki]) == 1
+
if __name__ == '__main__':
TransferTest().run_test()
diff --git a/tests/trezor/trezor_tests.cpp b/tests/trezor/trezor_tests.cpp
index 31c2471ec..a867a4047 100644
--- a/tests/trezor/trezor_tests.cpp
+++ b/tests/trezor/trezor_tests.cpp
@@ -304,7 +304,7 @@ static bool init_core_replay_events(std::vector<test_event_entry>& events, crypt
// Hardforks can be specified in events.
v_hardforks_t hardforks;
- cryptonote::test_options test_options_tmp{};
+ cryptonote::test_options test_options_tmp{nullptr, 0};
const cryptonote::test_options * test_options_ = &gto.test_options;
if (extract_hard_forks(events, hardforks)){
hardforks.push_back(std::make_pair((uint8_t)0, (uint64_t)0)); // terminator
diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp
index eb1ee8932..c8ce19ba4 100644
--- a/tests/unit_tests/ban.cpp
+++ b/tests/unit_tests/ban.cpp
@@ -93,18 +93,7 @@ typedef nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<test_cor
static bool is_blocked(Server &server, const epee::net_utils::network_address &address, time_t *t = NULL)
{
- const std::string host = address.host_str();
- std::map<std::string, time_t> hosts = server.get_blocked_hosts();
- for (auto rec: hosts)
- {
- if (rec.first == host)
- {
- if (t)
- *t = rec.second;
- return true;
- }
- }
- return false;
+ return server.is_host_blocked(address.host_str(), t);
}
TEST(ban, add)
@@ -192,5 +181,21 @@ TEST(ban, add)
ASSERT_TRUE(t >= 4);
}
+TEST(ban, limit)
+{
+ test_core pr_core;
+ cryptonote::t_cryptonote_protocol_handler<test_core> cprotocol(pr_core, NULL);
+ Server server(cprotocol);
+ cprotocol.set_p2p_endpoint(&server);
+
+ // starts empty
+ ASSERT_TRUE(server.get_blocked_hosts().empty());
+ ASSERT_FALSE(is_blocked(server,MAKE_IPV4_ADDRESS(1,2,3,4)));
+ ASSERT_TRUE(server.block_host(MAKE_IPV4_ADDRESS(1,2,3,4), std::numeric_limits<time_t>::max() - 1));
+ ASSERT_TRUE(is_blocked(server,MAKE_IPV4_ADDRESS(1,2,3,4)));
+ ASSERT_TRUE(server.block_host(MAKE_IPV4_ADDRESS(1,2,3,4), 1));
+ ASSERT_TRUE(is_blocked(server,MAKE_IPV4_ADDRESS(1,2,3,4)));
+}
+
namespace nodetool { template class node_server<cryptonote::t_cryptonote_protocol_handler<test_core>>; }
namespace cryptonote { template class t_cryptonote_protocol_handler<test_core>; }
diff --git a/tests/unit_tests/blockchain_db.cpp b/tests/unit_tests/blockchain_db.cpp
index 4fbc21ddc..f302d7946 100644
--- a/tests/unit_tests/blockchain_db.cpp
+++ b/tests/unit_tests/blockchain_db.cpp
@@ -271,6 +271,8 @@ TYPED_TEST(BlockchainDBTest, AddBlock)
this->get_filenames();
this->init_hard_fork();
+ db_wtxn_guard guard(this->m_db);
+
// adding a block with no parent in the blockchain should throw.
// note: this shouldn't be possible, but is a good (and cheap) failsafe.
//
@@ -317,6 +319,8 @@ TYPED_TEST(BlockchainDBTest, RetrieveBlockData)
this->get_filenames();
this->init_hard_fork();
+ db_wtxn_guard guard(this->m_db);
+
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0]));
ASSERT_EQ(t_sizes[0], this->m_db->get_block_weight(0));
diff --git a/tests/unit_tests/long_term_block_weight.cpp b/tests/unit_tests/long_term_block_weight.cpp
index bf1368618..b7713c63a 100644
--- a/tests/unit_tests/long_term_block_weight.cpp
+++ b/tests/unit_tests/long_term_block_weight.cpp
@@ -198,9 +198,10 @@ TEST(long_term_block_weight, multi_pop)
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
- for (uint64_t h = 0; h < 4; ++h)
+ const uint64_t num_pop = 4;
+ for (uint64_t h = 0; h < num_pop; ++h)
{
- size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
+ size_t w = bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
@@ -208,10 +209,8 @@ TEST(long_term_block_weight, multi_pop)
cryptonote::block b;
std::vector<cryptonote::transaction> txs;
- bc->get_db().pop_block(b, txs);
- bc->get_db().pop_block(b, txs);
- bc->get_db().pop_block(b, txs);
- bc->get_db().pop_block(b, txs);
+ for (uint64_t h = 0; h < num_pop; ++h)
+ bc->get_db().pop_block(b, txs);
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
ASSERT_EQ(effective_median, bc->get_current_cumulative_block_weight_median());
@@ -294,9 +293,11 @@ TEST(long_term_block_weight, pop_invariant_random)
{
PREFIX(10);
- for (uint64_t h = 1; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW - 10; ++h)
+ for (uint64_t h = 1; h < 2 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW - 10; ++h)
{
- size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
+ lcg_seed = bc->get_db().height();
+ uint32_t r = lcg();
+ size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : (r % bc->get_current_cumulative_block_weight_limit());
uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp
index e239154cf..4d51ec434 100644
--- a/tests/unit_tests/ringct.cpp
+++ b/tests/unit_tests/ringct.cpp
@@ -143,13 +143,16 @@ TEST(ringct, range_proofs)
//ct range proofs
ctkeyV sc, pc;
ctkey sctmp, pctmp;
- //add fake input 5000
- tie(sctmp, pctmp) = ctskpkGen(6000);
+ std::vector<uint64_t> inamounts;
+ //add fake input 6000
+ inamounts.push_back(6000);
+ tie(sctmp, pctmp) = ctskpkGen(inamounts.back());
sc.push_back(sctmp);
pc.push_back(pctmp);
- tie(sctmp, pctmp) = ctskpkGen(7000);
+ inamounts.push_back(7000);
+ tie(sctmp, pctmp) = ctskpkGen(inamounts.back());
sc.push_back(sctmp);
pc.push_back(pctmp);
vector<xmr_amount >amounts;
@@ -173,14 +176,20 @@ TEST(ringct, range_proofs)
const rct::RCTConfig rct_config { RangeProofBorromean, 0 };
- //compute rct data with mixin 500
- rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default"));
+ //compute rct data with mixin 3 - should fail since full type with > 1 input
+ bool ok = false;
+ try { genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default")); }
+ catch(...) { ok = true; }
+ ASSERT_TRUE(ok);
+
+ //compute rct data with mixin 3
+ rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config, hw::get_device("default"));
//verify rct data
- ASSERT_TRUE(verRct(s));
+ ASSERT_TRUE(verRctSimple(s));
//decode received amount
- decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default"));
+ decodeRctSimple(s, amount_keys[1], 1, mask, hw::get_device("default"));
// Ring CT with failing MG sig part should not verify!
// Since sum of inputs != outputs
@@ -190,14 +199,14 @@ TEST(ringct, range_proofs)
destinations[1] = Pk;
- //compute rct data with mixin 500
- s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default"));
+ //compute rct data with mixin 3
+ s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config, hw::get_device("default"));
//verify rct data
- ASSERT_FALSE(verRct(s));
+ ASSERT_FALSE(verRctSimple(s));
//decode received amount
- decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default"));
+ decodeRctSimple(s, amount_keys[1], 1, mask, hw::get_device("default"));
}
TEST(ringct, range_proofs_with_fee)
@@ -206,13 +215,16 @@ TEST(ringct, range_proofs_with_fee)
//ct range proofs
ctkeyV sc, pc;
ctkey sctmp, pctmp;
- //add fake input 5000
- tie(sctmp, pctmp) = ctskpkGen(6001);
+ std::vector<uint64_t> inamounts;
+ //add fake input 6001
+ inamounts.push_back(6001);
+ tie(sctmp, pctmp) = ctskpkGen(inamounts.back());
sc.push_back(sctmp);
pc.push_back(pctmp);
- tie(sctmp, pctmp) = ctskpkGen(7000);
+ inamounts.push_back(7000);
+ tie(sctmp, pctmp) = ctskpkGen(inamounts.back());
sc.push_back(sctmp);
pc.push_back(pctmp);
vector<xmr_amount >amounts;
@@ -227,10 +239,6 @@ TEST(ringct, range_proofs_with_fee)
skpkGen(Sk, Pk);
destinations.push_back(Pk);
- //add txn fee for 1
- //has no corresponding destination..
- amounts.push_back(1);
-
//add output for 12500
amounts.push_back(12500);
amount_keys.push_back(hash_to_scalar(zero()));
@@ -239,14 +247,14 @@ TEST(ringct, range_proofs_with_fee)
const rct::RCTConfig rct_config { RangeProofBorromean, 0 };
- //compute rct data with mixin 500
- rctSig s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default"));
+ //compute rct data with mixin 3
+ rctSig s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 1, 3, rct_config, hw::get_device("default"));
//verify rct data
- ASSERT_TRUE(verRct(s));
+ ASSERT_TRUE(verRctSimple(s));
//decode received amount
- decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default"));
+ decodeRctSimple(s, amount_keys[1], 1, mask, hw::get_device("default"));
// Ring CT with failing MG sig part should not verify!
// Since sum of inputs != outputs
@@ -256,14 +264,14 @@ TEST(ringct, range_proofs_with_fee)
destinations[1] = Pk;
- //compute rct data with mixin 500
- s = genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default"));
+ //compute rct data with mixin 3
+ s = genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 500, 3, rct_config, hw::get_device("default"));
//verify rct data
- ASSERT_FALSE(verRct(s));
+ ASSERT_FALSE(verRctSimple(s));
//decode received amount
- decodeRct(s, amount_keys[1], 1, mask, hw::get_device("default"));
+ decodeRctSimple(s, amount_keys[1], 1, mask, hw::get_device("default"));
}
TEST(ringct, simple)
@@ -538,10 +546,10 @@ TEST(ringct, range_proofs_accept_zero_out_middle_simple)
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true));
}
-TEST(ringct, range_proofs_accept_zero_in_first)
+TEST(ringct, range_proofs_accept_zero)
{
- const uint64_t inputs[] = {0, 5000};
- const uint64_t outputs[] = {5000};
+ const uint64_t inputs[] = {0};
+ const uint64_t outputs[] = {0};
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false));
}
@@ -552,13 +560,6 @@ TEST(ringct, range_proofs_accept_zero_in_first_simple)
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true));
}
-TEST(ringct, range_proofs_accept_zero_in_last)
-{
- const uint64_t inputs[] = {5000, 0};
- const uint64_t outputs[] = {5000};
- EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false));
-}
-
TEST(ringct, range_proofs_accept_zero_in_last_simple)
{
const uint64_t inputs[] = {5000, 0};
@@ -566,13 +567,6 @@ TEST(ringct, range_proofs_accept_zero_in_last_simple)
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true));
}
-TEST(ringct, range_proofs_accept_zero_in_middle)
-{
- const uint64_t inputs[] = {2500, 0, 2500};
- const uint64_t outputs[] = {5000};
- EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false));
-}
-
TEST(ringct, range_proofs_accept_zero_in_middle_simple)
{
const uint64_t inputs[] = {2500, 0, 2500};
@@ -762,13 +756,6 @@ TEST(ringct, range_proofs_accept_1_to_N_simple)
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false,true));
}
-TEST(ringct, range_proofs_accept_N_to_1)
-{
- const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000};
- const uint64_t outputs[] = {5000};
- EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false));
-}
-
TEST(ringct, range_proofs_accept_N_to_1_simple)
{
const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000};
@@ -776,13 +763,6 @@ TEST(ringct, range_proofs_accept_N_to_1_simple)
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true));
}
-TEST(ringct, range_proofs_accept_N_to_N)
-{
- const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000};
- const uint64_t outputs[] = {1000, 1000, 1000, 1000, 1000};
- EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false));
-}
-
TEST(ringct, range_proofs_accept_N_to_N_simple)
{
const uint64_t inputs[] = {1000, 1000, 1000, 1000, 1000};
@@ -790,20 +770,6 @@ TEST(ringct, range_proofs_accept_N_to_N_simple)
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, true));
}
-TEST(ringct, range_proofs_accept_very_long)
-{
- const size_t N=12;
- uint64_t inputs[N];
- uint64_t outputs[N];
- for (size_t n = 0; n < N; ++n) {
- inputs[n] = n;
- outputs[n] = n;
- }
- std::random_shuffle(inputs, inputs + N);
- std::random_shuffle(outputs, outputs + N);
- EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, false, false));
-}
-
TEST(ringct, range_proofs_accept_very_long_simple)
{
const size_t N=12;
@@ -861,7 +827,7 @@ TEST(ringct, prooveRange_is_non_deterministic)
TEST(ringct, fee_0_valid)
{
- const uint64_t inputs[] = {1000, 1000};
+ const uint64_t inputs[] = {2000};
const uint64_t outputs[] = {2000, 0};
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false));
}
@@ -875,7 +841,7 @@ TEST(ringct, fee_0_valid_simple)
TEST(ringct, fee_non_0_valid)
{
- const uint64_t inputs[] = {1000, 1000};
+ const uint64_t inputs[] = {2000};
const uint64_t outputs[] = {1900, 100};
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false));
}
@@ -917,7 +883,7 @@ TEST(ringct, fee_non_0_invalid_lower_simple)
TEST(ringct, fee_burn_valid_one_out)
{
- const uint64_t inputs[] = {1000, 1000};
+ const uint64_t inputs[] = {2000};
const uint64_t outputs[] = {0, 2000};
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false));
}
@@ -931,7 +897,7 @@ TEST(ringct, fee_burn_valid_one_out_simple)
TEST(ringct, fee_burn_valid_zero_out)
{
- const uint64_t inputs[] = {1000, 1000};
+ const uint64_t inputs[] = {2000};
const uint64_t outputs[] = {2000};
EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, false));
}
@@ -945,7 +911,7 @@ TEST(ringct, fee_burn_valid_zero_out_simple)
static rctSig make_sig()
{
- static const uint64_t inputs[] = {1000, 1000};
+ static const uint64_t inputs[] = {2000};
static const uint64_t outputs[] = {1000, 1000};
static rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true);
return sig;
@@ -1044,7 +1010,7 @@ TEST(ringct, reject_gen_simple_ver_non_simple)
TEST(ringct, reject_gen_non_simple_ver_simple)
{
- const uint64_t inputs[] = {1000, 1000};
+ const uint64_t inputs[] = {2000};
const uint64_t outputs[] = {1000, 1000};
rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true);
ASSERT_FALSE(rct::verRctSimple(sig));
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index 27b14ffff..23f028464 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -477,7 +477,7 @@ TEST(Serialization, serializes_ringct_types)
rct::ecdhTuple ecdh0, ecdh1;
rct::boroSig boro0, boro1;
rct::mgSig mg0, mg1;
- rct::rangeSig rg0, rg1;
+ rct::Bulletproof bp0, bp1;
rct::rctSig s0, s1;
cryptonote::transaction tx0, tx1;
@@ -566,12 +566,15 @@ TEST(Serialization, serializes_ringct_types)
ASSERT_TRUE(!memcmp(&boro0, &boro1, sizeof(boro0)));
// create a full rct signature to use its innards
+ vector<uint64_t> inamounts;
rct::ctkeyV sc, pc;
rct::ctkey sctmp, pctmp;
- tie(sctmp, pctmp) = rct::ctskpkGen(6000);
+ inamounts.push_back(6000);
+ tie(sctmp, pctmp) = rct::ctskpkGen(inamounts.back());
sc.push_back(sctmp);
pc.push_back(pctmp);
- tie(sctmp, pctmp) = rct::ctskpkGen(7000);
+ inamounts.push_back(7000);
+ tie(sctmp, pctmp) = rct::ctskpkGen(inamounts.back());
sc.push_back(sctmp);
pc.push_back(pctmp);
vector<uint64_t> amounts;
@@ -588,9 +591,9 @@ TEST(Serialization, serializes_ringct_types)
amount_keys.push_back(rct::hash_to_scalar(rct::zero()));
rct::skpkGen(Sk, Pk);
destinations.push_back(Pk);
- //compute rct data with mixin 500
+ //compute rct data with mixin 3
const rct::RCTConfig rct_config{ rct::RangeProofPaddedBulletproof, 0 };
- s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, rct_config, hw::get_device("default"));
+ s0 = rct::genRctSimple(rct::zero(), sc, pc, destinations, inamounts, amounts, amount_keys, NULL, NULL, 0, 3, rct_config, hw::get_device("default"));
mg0 = s0.p.MGs[0];
ASSERT_TRUE(serialization::dump_binary(mg0, blob));
@@ -605,66 +608,12 @@ TEST(Serialization, serializes_ringct_types)
// mixRing and II are not serialized, they are meant to be reconstructed
ASSERT_TRUE(mg1.II.empty());
- rg0 = s0.p.rangeSigs.front();
- ASSERT_TRUE(serialization::dump_binary(rg0, blob));
- ASSERT_TRUE(serialization::parse_binary(blob, rg1));
- ASSERT_TRUE(!memcmp(&rg0, &rg1, sizeof(rg0)));
-
-#if 0
- ASSERT_TRUE(serialization::dump_binary(s0, blob));
- ASSERT_TRUE(serialization::parse_binary(blob, s1));
- ASSERT_TRUE(s0.type == s1.type);
- ASSERT_TRUE(s0.p.rangeSigs.size() == s1.p.rangeSigs.size());
- for (size_t n = 0; n < s0.p.rangeSigs.size(); ++n)
- {
- ASSERT_TRUE(!memcmp(&s0.p.rangeSigs[n], &s1.p.rangeSigs[n], sizeof(s0.p.rangeSigs[n])));
- }
- ASSERT_TRUE(s0.p.MGs.size() == s1.p.MGs.size());
- ASSERT_TRUE(s0.p.MGs[0].ss.size() == s1.p.MGs[0].ss.size());
- for (size_t n = 0; n < s0.p.MGs[0].ss.size(); ++n)
- {
- ASSERT_TRUE(s0.p.MGs[0].ss[n] == s1.p.MGs[0].ss[n]);
- }
- ASSERT_TRUE(s0.p.MGs[0].cc == s1.p.MGs[0].cc);
- // mixRing and II are not serialized, they are meant to be reconstructed
- ASSERT_TRUE(s1.p.MGs[0].II.empty());
-
- // mixRing and II are not serialized, they are meant to be reconstructed
- ASSERT_TRUE(s1.mixRing.size() == 0);
-
- ASSERT_TRUE(s0.ecdhInfo.size() == s1.ecdhInfo.size());
- for (size_t n = 0; n < s0.ecdhInfo.size(); ++n)
- {
- ASSERT_TRUE(!memcmp(&s0.ecdhInfo[n], &s1.ecdhInfo[n], sizeof(s0.ecdhInfo[n])));
- }
- ASSERT_TRUE(s0.outPk.size() == s1.outPk.size());
- for (size_t n = 0; n < s0.outPk.size(); ++n)
- {
- // serialization only does the mask
- ASSERT_TRUE(!memcmp(&s0.outPk[n].mask, &s1.outPk[n].mask, sizeof(s0.outPk[n].mask)));
- }
-#endif
-
- tx0.set_null();
- tx0.version = 2;
- cryptonote::txin_to_key txin_to_key1{};
- txin_to_key1.amount = 100;
- txin_to_key1.key_offsets.resize(4);
- cryptonote::txin_to_key txin_to_key2{};
- txin_to_key2.amount = 200;
- txin_to_key2.key_offsets.resize(4);
- tx0.vin.push_back(txin_to_key1);
- tx0.vin.push_back(txin_to_key2);
- tx0.vout.push_back(cryptonote::tx_out());
- tx0.vout.push_back(cryptonote::tx_out());
- tx0.rct_signatures = s0;
- ASSERT_EQ(tx0.rct_signatures.p.rangeSigs.size(), 2);
- ASSERT_TRUE(serialization::dump_binary(tx0, blob));
- ASSERT_TRUE(serialization::parse_binary(blob, tx1));
- ASSERT_EQ(tx1.rct_signatures.p.rangeSigs.size(), 2);
- std::string blob2;
- ASSERT_TRUE(serialization::dump_binary(tx1, blob2));
- ASSERT_TRUE(blob == blob2);
+ ASSERT_FALSE(s0.p.bulletproofs.empty());
+ bp0 = s0.p.bulletproofs.front();
+ ASSERT_TRUE(serialization::dump_binary(bp0, blob));
+ ASSERT_TRUE(serialization::parse_binary(blob, bp1));
+ bp1.V = bp0.V; // this is not saved, as it is reconstructed from other tx data
+ ASSERT_EQ(bp0, bp1);
}
TEST(Serialization, portability_wallet)
diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py
index f4d5e90f0..04fc5b5cf 100644
--- a/utils/python-rpc/framework/daemon.py
+++ b/utils/python-rpc/framework/daemon.py
@@ -50,10 +50,11 @@ class Daemon(object):
}
return self.rpc.send_json_rpc_request(getblocktemplate)
- def send_raw_transaction(self, tx_as_hex, do_not_relay = False):
+ def send_raw_transaction(self, tx_as_hex, do_not_relay = False, do_sanity_checks = True):
send_raw_transaction = {
'tx_as_hex': tx_as_hex,
'do_not_relay': do_not_relay,
+ 'do_sanity_checks': do_sanity_checks,
}
return self.rpc.send_request("/send_raw_transaction", send_raw_transaction)
diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py
index a80aaefec..695325a86 100644
--- a/utils/python-rpc/framework/wallet.py
+++ b/utils/python-rpc/framework/wallet.py
@@ -184,6 +184,27 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(sweep_all)
+ def sweep_single(self, address = '', priority = 0, ring_size = 0, outputs = 1, unlock_time = 0, payment_id = '', get_tx_keys = False, key_image = "", do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
+ sweep_single = {
+ 'method': 'sweep_single',
+ 'params' : {
+ 'address' : address,
+ 'priority' : priority,
+ 'ring_size' : ring_size,
+ 'outputs' : outputs,
+ 'unlock_time' : unlock_time,
+ 'payment_id' : payment_id,
+ 'get_tx_keys' : get_tx_keys,
+ 'key_image' : key_image,
+ 'do_not_relay' : do_not_relay,
+ 'get_tx_hex' : get_tx_hex,
+ 'get_tx_metadata' : get_tx_metadata,
+ },
+ 'jsonrpc': '2.0',
+ 'id': '0'
+ }
+ return self.rpc.send_json_rpc_request(sweep_single)
+
def get_address(self, account_index = 0, subaddresses = []):
get_address = {
'method': 'get_address',
@@ -265,7 +286,7 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(query_key)
- def restore_deterministic_wallet(self, seed = '', seed_offset = '', filename = '', restore_height = 0, password = '', language = ''):
+ def restore_deterministic_wallet(self, seed = '', seed_offset = '', filename = '', restore_height = 0, password = '', language = '', autosave_current = True):
restore_deterministic_wallet = {
'method': 'restore_deterministic_wallet',
'params' : {
@@ -274,14 +295,15 @@ class Wallet(object):
'seed': seed,
'seed_offset': seed_offset,
'password': password,
- 'language': language
+ 'language': language,
+ 'autosave_current': autosave_current,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(restore_deterministic_wallet)
- def generate_from_keys(self, restore_height = 0, filename = "", password = "", address = "", spendkey = "", viewkey = ""):
+ def generate_from_keys(self, restore_height = 0, filename = "", password = "", address = "", spendkey = "", viewkey = "", autosave_current = True):
generate_from_keys = {
'method': 'generate_from_keys',
'params' : {
@@ -291,16 +313,31 @@ class Wallet(object):
'spendkey': spendkey,
'viewkey': viewkey,
'password': password,
+ 'autosave_current': autosave_current,
},
'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(generate_from_keys)
- def close_wallet(self):
+ def open_wallet(self, filename, password='', autosave_current = True):
+ open_wallet = {
+ 'method': 'open_wallet',
+ 'params' : {
+ 'filename': filename,
+ 'password': password,
+ 'autosave_current': autosave_current,
+ },
+ 'jsonrpc': '2.0',
+ 'id': '0'
+ }
+ return self.rpc.send_json_rpc_request(open_wallet)
+
+ def close_wallet(self, autosave_current = True):
close_wallet = {
'method': 'close_wallet',
'params' : {
+ 'autosave_current': autosave_current
},
'jsonrpc': '2.0',
'id': '0'