aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--contrib/depends/packages/sodium.mk4
-rw-r--r--contrib/depends/patches/sodium/fix-whitespace.patch4
-rw-r--r--contrib/epee/include/console_handler.h9
-rw-r--r--contrib/epee/include/md5_l.h2
-rw-r--r--contrib/epee/include/net/http_server_handlers_map2.h2
-rw-r--r--contrib/epee/include/string_tools.h4
-rw-r--r--src/CMakeLists.txt6
-rw-r--r--src/common/perf_timer.h4
-rw-r--r--src/common/threadpool.cpp31
-rw-r--r--src/common/threadpool.h5
-rw-r--r--src/crypto/blake256.c9
-rw-r--r--src/cryptonote_core/blockchain.cpp7
-rw-r--r--src/p2p/net_node.inl1
-rw-r--r--src/rpc/daemon_handler.cpp16
-rw-r--r--src/simplewallet/simplewallet.cpp2
-rw-r--r--src/wallet/CMakeLists.txt65
-rw-r--r--src/wallet/wallet2.cpp18
-rw-r--r--src/wallet/wallet2.h2
-rw-r--r--src/wallet/wallet_rpc_server.cpp45
-rw-r--r--src/wallet/wallet_rpc_server.h2
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h45
-rw-r--r--tests/core_tests/chaingen.cpp188
-rw-r--r--tests/core_tests/chaingen.h13
-rw-r--r--tests/core_tests/wallet_tools.cpp3
-rw-r--r--utils/gpg_keys/binaryfate.asc87
-rw-r--r--utils/gpg_keys/snipa.asc52
-rw-r--r--utils/python-rpc/framework/wallet.py21
-rwxr-xr-xutils/translations/build-translations.sh6
29 files changed, 555 insertions, 100 deletions
diff --git a/.gitignore b/.gitignore
index 0ece7cb75..08c310e66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -107,3 +107,5 @@ nbproject
.idea/
/testnet
+
+__pycache__/
diff --git a/contrib/depends/packages/sodium.mk b/contrib/depends/packages/sodium.mk
index dbf86fc5a..462bd2415 100644
--- a/contrib/depends/packages/sodium.mk
+++ b/contrib/depends/packages/sodium.mk
@@ -1,8 +1,8 @@
package=sodium
-$(package)_version=1.0.16
+$(package)_version=1.0.18
$(package)_download_path=https://download.libsodium.org/libsodium/releases/
$(package)_file_name=libsodium-$($(package)_version).tar.gz
-$(package)_sha256_hash=eeadc7e1e1bcef09680fb4837d448fbdf57224978f865ac1c16745868fbd0533
+$(package)_sha256_hash=6f504490b342a4f8a4c4a02fc9b866cbef8622d5df4e5452b46be121e46636c1
$(package)_patches=fix-whitespace.patch
define $(package)_set_vars
diff --git a/contrib/depends/patches/sodium/fix-whitespace.patch b/contrib/depends/patches/sodium/fix-whitespace.patch
index efbfe4e83..c3d3af0b4 100644
--- a/contrib/depends/patches/sodium/fix-whitespace.patch
+++ b/contrib/depends/patches/sodium/fix-whitespace.patch
@@ -5,8 +5,8 @@ index b29f769..ca008ae 100755
@@ -591,7 +591,7 @@ MAKEFLAGS=
PACKAGE_NAME='libsodium'
PACKAGE_TARNAME='libsodium'
- PACKAGE_VERSION='1.0.16'
--PACKAGE_STRING='libsodium 1.0.16'
+ PACKAGE_VERSION='1.0.18'
+-PACKAGE_STRING='libsodium 1.0.18'
+PACKAGE_STRING='libsodium'
PACKAGE_BUGREPORT='https://github.com/jedisct1/libsodium/issues'
PACKAGE_URL='https://github.com/jedisct1/libsodium'
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h
index 13747b0c8..1b716fca4 100644
--- a/contrib/epee/include/console_handler.h
+++ b/contrib/epee/include/console_handler.h
@@ -605,10 +605,17 @@ eof:
std::unique_ptr<boost::thread> m_console_thread;
async_console_handler m_console_handler;
public:
+ ~console_handlers_binder() {
+ stop_handling();
+ if (m_console_thread.get() != nullptr)
+ {
+ m_console_thread->join();
+ }
+ }
+
bool start_handling(std::function<std::string(void)> prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
{
m_console_thread.reset(new boost::thread(boost::bind(&console_handlers_binder::run_handling, this, prompt, usage_string, exit_handler)));
- m_console_thread->detach();
return true;
}
bool start_handling(const std::string &prompt, const std::string& usage_string = "", std::function<void(void)> exit_handler = NULL)
diff --git a/contrib/epee/include/md5_l.h b/contrib/epee/include/md5_l.h
index a45d91bc8..bc7122650 100644
--- a/contrib/epee/include/md5_l.h
+++ b/contrib/epee/include/md5_l.h
@@ -85,7 +85,7 @@ namespace md5
MD5Update( &ctx, input, ilen );
MD5Final( output, &ctx);
- memset( &ctx, 0, sizeof( MD5_CTX) );
+ memwipe( &ctx, sizeof( MD5_CTX ));
return true;
}
diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h
index 07ed8157b..0c0653cd6 100644
--- a/contrib/epee/include/net/http_server_handlers_map2.h
+++ b/contrib/epee/include/net/http_server_handlers_map2.h
@@ -120,6 +120,7 @@
#define BEGIN_JSON_RPC_MAP(uri) else if(query_info.m_URI == uri) \
{ \
uint64_t ticks = epee::misc_utils::get_tick_count(); \
+ response_info.m_mime_tipe = "application/json"; \
epee::serialization::portable_storage ps; \
if(!ps.load_from_json(query_info.m_body)) \
{ \
@@ -148,6 +149,7 @@
#define PREPARE_OBJECTS_FROM_JSON(command_type) \
handled = true; \
+ response_info.m_mime_tipe = "application/json"; \
boost::value_initialized<epee::json_rpc::request<command_type::request> > req_; \
epee::json_rpc::request<command_type::request>& req = static_cast<epee::json_rpc::request<command_type::request>&>(req_);\
if(!req.load(ps)) \
diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h
index 1be5eb5e1..319c0121b 100644
--- a/contrib/epee/include/string_tools.h
+++ b/contrib/epee/include/string_tools.h
@@ -188,8 +188,10 @@ POP_WARNINGS
return boost::lexical_cast<std::string>(val);
}
//----------------------------------------------------------------------------
- inline std::string to_string_hex(uint32_t val)
+ template<typename T>
+ inline std::string to_string_hex(const T &val)
{
+ static_assert(std::is_arithmetic<T>::value, "only arithmetic types");
std::stringstream ss;
ss << std::hex << val;
std::string s;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f332af3d3..d45363e24 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -113,12 +113,10 @@ add_subdirectory(lmdb)
add_subdirectory(multisig)
add_subdirectory(net)
add_subdirectory(hardforks)
-if(NOT IOS)
- add_subdirectory(blockchain_db)
-endif()
+add_subdirectory(blockchain_db)
add_subdirectory(mnemonics)
+add_subdirectory(rpc)
if(NOT IOS)
- add_subdirectory(rpc)
add_subdirectory(serialization)
endif()
add_subdirectory(wallet)
diff --git a/src/common/perf_timer.h b/src/common/perf_timer.h
index ea2237348..29a37e655 100644
--- a/src/common/perf_timer.h
+++ b/src/common/perf_timer.h
@@ -84,7 +84,7 @@ void set_performance_timer_log_level(el::Level level);
#define PERF_TIMER_START_UNIT(name, unit) std::unique_ptr<tools::LoggingPerformanceTimer> PERF_TIMER_NAME(name)(new tools::LoggingPerformanceTimer(#name, "perf." MONERO_DEFAULT_LOG_CATEGORY, unit, el::Level::Info))
#define PERF_TIMER_START(name) PERF_TIMER_START_UNIT(name, 1000000)
#define PERF_TIMER_STOP(name) do { PERF_TIMER_NAME(name).reset(NULL); } while(0)
-#define PERF_TIMER_PAUSE(name) PERF_TIMER_NAME(name)->pause()
-#define PERF_TIMER_RESUME(name) PERF_TIMER_NAME(name)->resume()
+#define PERF_TIMER_PAUSE(name) PERF_TIMER_NAME(name).pause()
+#define PERF_TIMER_RESUME(name) PERF_TIMER_NAME(name).resume()
}
diff --git a/src/common/threadpool.cpp b/src/common/threadpool.cpp
index 2748c798c..18204eeee 100644
--- a/src/common/threadpool.cpp
+++ b/src/common/threadpool.cpp
@@ -37,16 +37,14 @@ static __thread bool is_leaf = false;
namespace tools
{
threadpool::threadpool(unsigned int max_threads) : running(true), active(0) {
- boost::thread::attributes attrs;
- attrs.set_stack_size(THREAD_STACK_SIZE);
- max = max_threads ? max_threads : tools::get_max_concurrency();
- size_t i = max ? max - 1 : 0;
- while(i--) {
- threads.push_back(boost::thread(attrs, boost::bind(&threadpool::run, this, false)));
- }
+ create(max_threads);
}
threadpool::~threadpool() {
+ destroy();
+}
+
+void threadpool::destroy() {
try
{
const boost::unique_lock<boost::mutex> lock(mutex);
@@ -64,6 +62,23 @@ threadpool::~threadpool() {
try { threads[i].join(); }
catch (...) { /* ignore */ }
}
+ threads.clear();
+}
+
+void threadpool::recycle() {
+ destroy();
+ create(max);
+}
+
+void threadpool::create(unsigned int max_threads) {
+ boost::thread::attributes attrs;
+ attrs.set_stack_size(THREAD_STACK_SIZE);
+ max = max_threads ? max_threads : tools::get_max_concurrency();
+ size_t i = max ? max - 1 : 0;
+ running = true;
+ while(i--) {
+ threads.push_back(boost::thread(attrs, boost::bind(&threadpool::run, this, false)));
+ }
}
void threadpool::submit(waiter *obj, std::function<void()> f, bool leaf) {
@@ -145,7 +160,7 @@ void threadpool::run(bool flush) {
if (!running) break;
active++;
- e = queue.front();
+ e = std::move(queue.front());
queue.pop_front();
lock.unlock();
++depth;
diff --git a/src/common/threadpool.h b/src/common/threadpool.h
index 5e490ee7d..a49d0e14f 100644
--- a/src/common/threadpool.h
+++ b/src/common/threadpool.h
@@ -69,12 +69,17 @@ public:
// task to finish.
void submit(waiter *waiter, std::function<void()> f, bool leaf = false);
+ // destroy and recreate threads
+ void recycle();
+
unsigned int get_max_concurrency() const;
~threadpool();
private:
threadpool(unsigned int max_threads = 0);
+ void destroy();
+ void create(unsigned int max_threads);
typedef struct entry {
waiter *wo;
std::function<void()> f;
diff --git a/src/crypto/blake256.c b/src/crypto/blake256.c
index 1e305b3a6..bb2c5fb40 100644
--- a/src/crypto/blake256.c
+++ b/src/crypto/blake256.c
@@ -40,6 +40,7 @@
#include <string.h>
#include <stdio.h>
#include <stdint.h>
+#include <memwipe.h>
#include "blake256.h"
#define U8TO32(p) \
@@ -277,7 +278,7 @@ void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
}
blake256_update(&S->outer, pad, 512);
- memset(keyhash, 0, 32);
+ memwipe(keyhash, sizeof(keyhash));
}
// keylen = number of bytes
@@ -307,7 +308,7 @@ void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
}
blake224_update(&S->outer, pad, 512);
- memset(keyhash, 0, 32);
+ memwipe(keyhash, sizeof(keyhash));
}
// datalen = number of bits
@@ -327,7 +328,7 @@ void hmac_blake256_final(hmac_state *S, uint8_t *digest) {
blake256_final(&S->inner, ihash);
blake256_update(&S->outer, ihash, 256);
blake256_final(&S->outer, digest);
- memset(ihash, 0, 32);
+ memwipe(ihash, sizeof(ihash));
}
void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
@@ -335,7 +336,7 @@ void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
blake224_final(&S->inner, ihash);
blake224_update(&S->outer, ihash, 224);
blake224_final(&S->outer, digest);
- memset(ihash, 0, 32);
+ memwipe(ihash, sizeof(ihash));
}
// keylen = number of bytes; inlen = number of bytes
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 7357e44d0..5070cc169 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -5079,7 +5079,12 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
return;
}
const size_t size_needed = 4 + nblocks * (sizeof(crypto::hash) * 2);
- if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && checkpoints.size() >= size_needed)
+ if(checkpoints.size() != size_needed)
+ {
+ MERROR("Failed to load hashes - unexpected data size");
+ return;
+ }
+ else if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP)
{
p += sizeof(uint32_t);
m_blocks_hash_of_hashes.reserve(nblocks);
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 5dab251b5..72edddf77 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -1884,6 +1884,7 @@ namespace nodetool
--i;
continue;
}
+ local_peerlist[i].last_seen = 0;
#ifdef CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED
be.pruning_seed = tools::make_pruning_seed(1 + (be.adr.as<epee::net_utils::ipv4_network_address>().ip()) % (1ul << CRYPTONOTE_PRUNING_LOG_STRIPES), CRYPTONOTE_PRUNING_LOG_STRIPES);
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index 0b6cd6c7a..24800ff20 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -311,42 +311,42 @@ namespace rpc
if (tvc.m_double_spend)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "double spend";
+ res.error_details += "double spend";
}
if (tvc.m_invalid_input)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "invalid input";
+ res.error_details += "invalid input";
}
if (tvc.m_invalid_output)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "invalid output";
+ res.error_details += "invalid output";
}
if (tvc.m_too_big)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "too big";
+ res.error_details += "too big";
}
if (tvc.m_overspend)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "overspend";
+ res.error_details += "overspend";
}
if (tvc.m_fee_too_low)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "fee too low";
+ res.error_details += "fee too low";
}
if (tvc.m_not_rct)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "tx is not ringct";
+ res.error_details += "tx is not ringct";
}
if (tvc.m_too_few_outputs)
{
if (!res.error_details.empty()) res.error_details += " and ";
- res.error_details = "too few outputs";
+ res.error_details += "too few outputs";
}
if (res.error_details.empty())
{
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index a35ee40ae..87bbf62d3 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -4346,7 +4346,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (std::cin.eof() || !command_line::is_yes(confirm))
CHECK_AND_ASSERT_MES(false, false, tr("account creation aborted"));
- m_wallet->set_refresh_from_block_height(m_wallet->estimate_blockchain_height());
+ m_wallet->set_refresh_from_block_height(m_wallet->estimate_blockchain_height() > 0 ? m_wallet->estimate_blockchain_height() - 1 : 0);
m_wallet->explicit_refresh_from_block_height(true);
m_restore_height = m_wallet->get_refresh_from_block_height();
}
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 3be1a6f6b..a0a166a93 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -77,42 +77,43 @@ target_link_libraries(wallet
PRIVATE
${EXTRA_LIBRARIES})
-set(wallet_rpc_sources
- wallet_rpc_server.cpp)
+if(NOT IOS)
+ set(wallet_rpc_sources
+ wallet_rpc_server.cpp)
-set(wallet_rpc_headers)
+ set(wallet_rpc_headers)
-set(wallet_rpc_private_headers
- wallet_rpc_server.h)
+ set(wallet_rpc_private_headers
+ wallet_rpc_server.h)
-monero_private_headers(wallet_rpc_server
- ${wallet_rpc_private_headers})
-monero_add_executable(wallet_rpc_server
- ${wallet_rpc_sources}
- ${wallet_rpc_headers}
- ${wallet_rpc_private_headers})
-
-target_link_libraries(wallet_rpc_server
- PRIVATE
- wallet
- rpc_base
- cryptonote_core
- cncrypto
- common
- version
- daemonizer
- ${EPEE_READLINE}
- ${Boost_CHRONO_LIBRARY}
- ${Boost_PROGRAM_OPTIONS_LIBRARY}
- ${Boost_FILESYSTEM_LIBRARY}
- ${Boost_THREAD_LIBRARY}
- ${CMAKE_THREAD_LIBS_INIT}
- ${EXTRA_LIBRARIES})
-set_property(TARGET wallet_rpc_server
- PROPERTY
- OUTPUT_NAME "monero-wallet-rpc")
-install(TARGETS wallet_rpc_server DESTINATION bin)
+ monero_private_headers(wallet_rpc_server
+ ${wallet_rpc_private_headers})
+ monero_add_executable(wallet_rpc_server
+ ${wallet_rpc_sources}
+ ${wallet_rpc_headers}
+ ${wallet_rpc_private_headers})
+ target_link_libraries(wallet_rpc_server
+ PRIVATE
+ wallet
+ rpc_base
+ cryptonote_core
+ cncrypto
+ common
+ version
+ daemonizer
+ ${EPEE_READLINE}
+ ${Boost_CHRONO_LIBRARY}
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY}
+ ${Boost_THREAD_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${EXTRA_LIBRARIES})
+ set_property(TARGET wallet_rpc_server
+ PROPERTY
+ OUTPUT_NAME "monero-wallet-rpc")
+ install(TARGETS wallet_rpc_server DESTINATION bin)
+endif()
# build and install libwallet_merged only if we building for GUI
if (BUILD_GUI_DEPS)
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index ea556ec45..4d2ec5103 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -13619,4 +13619,22 @@ std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
std::copy(res.gray.begin(), res.gray.end(), std::back_inserter(nodes));
return nodes;
}
+//----------------------------------------------------------------------------------------------------
+std::pair<size_t, uint64_t> wallet2::estimate_tx_size_and_weight(bool use_rct, int n_inputs, int ring_size, int n_outputs, size_t extra_size)
+{
+ THROW_WALLET_EXCEPTION_IF(n_inputs <= 0, tools::error::wallet_internal_error, "Invalid n_inputs");
+ THROW_WALLET_EXCEPTION_IF(n_outputs < 0, tools::error::wallet_internal_error, "Invalid n_outputs");
+ THROW_WALLET_EXCEPTION_IF(ring_size < 0, tools::error::wallet_internal_error, "Invalid ring size");
+
+ if (ring_size == 0)
+ ring_size = get_min_ring_size();
+ if (n_outputs == 1)
+ n_outputs = 2; // extra dummy output
+
+ const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
+ size_t size = estimate_tx_size(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof);
+ uint64_t weight = estimate_tx_weight(use_rct, n_inputs, ring_size - 1, n_outputs, extra_size, bulletproof);
+ return std::make_pair(size, weight);
+}
+//----------------------------------------------------------------------------------------------------
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index b6f72c7e1..8f840a42d 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -1254,6 +1254,8 @@ private:
bool is_unattended() const { return m_unattended; }
+ std::pair<size_t, uint64_t> estimate_tx_size_and_weight(bool use_rct, int n_inputs, int ring_size, int n_outputs, size_t extra_size);
+
bool get_rpc_payment_info(bool mining, bool &payment_required, uint64_t &credits, uint64_t &diff, uint64_t &credits_per_hash_found, cryptonote::blobdata &hashing_blob, uint64_t &height, uint64_t &seed_height, crypto::hash &seed_hash, crypto::hash &next_seed_hash, uint32_t &cookie);
bool daemon_requires_payment();
bool make_rpc_payment(uint32_t nonce, uint32_t cookie, uint64_t &credits, uint64_t &balance);
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index de501f056..eb89a96e9 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -550,9 +550,29 @@ namespace tools
if (!m_wallet) return not_open(er);
try
{
- m_wallet->add_subaddress(req.account_index, req.label);
- res.address_index = m_wallet->get_num_subaddresses(req.account_index) - 1;
- res.address = m_wallet->get_subaddress_as_str({req.account_index, res.address_index});
+ if (req.count < 1 || req.count > 64) {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Count must be between 1 and 64.";
+ return false;
+ }
+
+ std::vector<std::string> addresses;
+ std::vector<uint32_t> address_indices;
+
+ addresses.reserve(req.count);
+ address_indices.reserve(req.count);
+
+ for (uint32_t i = 0; i < req.count; i++) {
+ m_wallet->add_subaddress(req.account_index, req.label);
+ uint32_t new_address_index = m_wallet->get_num_subaddresses(req.account_index) - 1;
+ address_indices.push_back(new_address_index);
+ addresses.push_back(m_wallet->get_subaddress_as_str({req.account_index, new_address_index}));
+ }
+
+ res.address = addresses[0];
+ res.address_index = address_indices[0];
+ res.addresses = addresses;
+ res.address_indices = address_indices;
}
catch (const std::exception& e)
{
@@ -4291,6 +4311,25 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_estimate_tx_size_and_weight(const wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::request& req, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::response& res, epee::json_rpc::error& er, const connection_context *ctx)
+ {
+ if (!m_wallet) return not_open(er);
+ try
+ {
+ size_t extra_size = 34 /* pubkey */ + 10 /* encrypted payment id */; // typical makeup
+ const std::pair<size_t, uint64_t> sw = m_wallet->estimate_tx_size_and_weight(req.rct, req.n_inputs, req.ring_size, req.n_outputs, extra_size);
+ res.size = sw.first;
+ res.weight = sw.second;
+ }
+ catch (const std::exception &e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to determine size and weight";
+ return false;
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_version(const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& er, const connection_context *ctx)
{
res.version = WALLET_RPC_VERSION;
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index b2b5e7116..41f6879ef 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -154,6 +154,7 @@ namespace tools
MAP_JON_RPC_WE("set_daemon", on_set_daemon, wallet_rpc::COMMAND_RPC_SET_DAEMON)
MAP_JON_RPC_WE("set_log_level", on_set_log_level, wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL)
MAP_JON_RPC_WE("set_log_categories", on_set_log_categories, wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES)
+ MAP_JON_RPC_WE("estimate_tx_size_and_weight", on_estimate_tx_size_and_weight, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT)
MAP_JON_RPC_WE("get_version", on_get_version, wallet_rpc::COMMAND_RPC_GET_VERSION)
END_JSON_RPC_MAP()
END_URI_MAP2()
@@ -240,6 +241,7 @@ namespace tools
bool on_set_daemon(const wallet_rpc::COMMAND_RPC_SET_DAEMON::request& req, wallet_rpc::COMMAND_RPC_SET_DAEMON::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_set_log_level(const wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL::request& req, wallet_rpc::COMMAND_RPC_SET_LOG_LEVEL::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_set_log_categories(const wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::request& req, wallet_rpc::COMMAND_RPC_SET_LOG_CATEGORIES::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
+ bool on_estimate_tx_size_and_weight(const wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::request& req, wallet_rpc::COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
bool on_get_version(const wallet_rpc::COMMAND_RPC_GET_VERSION::request& req, wallet_rpc::COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& er, const connection_context *ctx = NULL);
//json rpc v2
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 0c86f404d..8d601b050 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 16
+#define WALLET_RPC_VERSION_MINOR 17
#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
@@ -182,11 +182,13 @@ namespace wallet_rpc
{
struct request_t
{
- uint32_t account_index;
+ uint32_t account_index;
+ uint32_t count;
std::string label;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
+ KV_SERIALIZE_OPT(count, 1U)
KV_SERIALIZE(label)
END_KV_SERIALIZE_MAP()
};
@@ -194,12 +196,16 @@ namespace wallet_rpc
struct response_t
{
- std::string address;
- uint32_t address_index;
+ std::string address;
+ uint32_t address_index;
+ std::vector<std::string> addresses;
+ std::vector<uint32_t> address_indices;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(address_index)
+ KV_SERIALIZE(addresses)
+ KV_SERIALIZE(address_indices)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
@@ -2580,5 +2586,36 @@ namespace wallet_rpc
typedef epee::misc_utils::struct_init<response_t> response;
};
+ struct COMMAND_RPC_ESTIMATE_TX_SIZE_AND_WEIGHT
+ {
+ struct request_t
+ {
+ uint32_t n_inputs;
+ uint32_t n_outputs;
+ uint32_t ring_size;
+ bool rct;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(n_inputs)
+ KV_SERIALIZE(n_outputs)
+ KV_SERIALIZE_OPT(ring_size, 0u)
+ KV_SERIALIZE_OPT(rct, true)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct response_t
+ {
+ uint64_t size;
+ uint64_t weight;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(size)
+ KV_SERIALIZE(weight)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+
}
}
diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp
index 35e449e10..c38ea614c 100644
--- a/tests/core_tests/chaingen.cpp
+++ b/tests/core_tests/chaingen.cpp
@@ -47,6 +47,12 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/miner.h"
+#include "blockchain_db/blockchain_db.h"
+#include "cryptonote_core/cryptonote_core.h"
+#include "cryptonote_core/tx_pool.h"
+#include "cryptonote_core/blockchain.h"
+#include "blockchain_db/testdb.h"
+
#include "chaingen.h"
#include "device/device.hpp"
using namespace std;
@@ -55,6 +61,126 @@ using namespace epee;
using namespace crypto;
using namespace cryptonote;
+namespace
+{
+ /**
+ * Dummy TestDB to store height -> (block, hash) information
+ * for the use only in the test_generator::fill_nonce() function,
+ * which requires blockchain object to correctly compute PoW on HF12+ blocks
+ * as the mining function requires it to obtain a valid seedhash.
+ */
+ class TestDB: public cryptonote::BaseTestDB
+ {
+ private:
+ struct block_t
+ {
+ cryptonote::block bl;
+ crypto::hash hash;
+ };
+
+ public:
+ TestDB() { m_open = true; }
+
+ virtual void add_block( const cryptonote::block& blk
+ , size_t block_weight
+ , uint64_t long_term_block_weight
+ , const cryptonote::difficulty_type& cumulative_difficulty
+ , const uint64_t& coins_generated
+ , uint64_t num_rct_outs
+ , const crypto::hash& blk_hash
+ ) override
+ {
+ blocks.push_back({blk, blk_hash});
+ }
+
+ virtual uint64_t height() const override { return blocks.empty() ? 0 : blocks.size() - 1; }
+
+ // Required for randomx
+ virtual crypto::hash get_block_hash_from_height(const uint64_t &height) const override
+ {
+ if (height < blocks.size())
+ {
+ MDEBUG("Get hash for block height: " << height << " hash: " << blocks[height].hash);
+ return blocks[height].hash;
+ }
+
+ MDEBUG("Get hash for block height: " << height << " zero-hash");
+ crypto::hash hash = crypto::null_hash;
+ *(uint64_t*)&hash = height;
+ return hash;
+ }
+
+ virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const override
+ {
+ const uint64_t h = height();
+ if (block_height != nullptr)
+ {
+ *block_height = h;
+ }
+
+ return get_block_hash_from_height(h);
+ }
+
+ virtual cryptonote::block get_top_block() const override
+ {
+ if (blocks.empty())
+ {
+ cryptonote::block b;
+ return b;
+ }
+
+ return blocks[blocks.size()-1].bl;
+ }
+
+ virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { if (!blocks.empty()) blocks.pop_back(); }
+ virtual void set_hard_fork_version(uint64_t height, uint8_t version) override { if (height >= hf.size()) hf.resize(height + 1); hf[height] = version; }
+ virtual uint8_t get_hard_fork_version(uint64_t height) const override { if (height >= hf.size()) return 255; return hf[height]; }
+
+ private:
+ std::vector<block_t> blocks;
+ std::vector<uint8_t> hf;
+ };
+
+}
+
+static std::unique_ptr<cryptonote::Blockchain> init_blockchain(const std::vector<test_event_entry> & events, cryptonote::network_type nettype)
+{
+ std::unique_ptr<cryptonote::Blockchain> bc;
+ v_hardforks_t hardforks;
+ cryptonote::test_options test_options_tmp{nullptr, 0};
+ const cryptonote::test_options * test_options = &test_options_tmp;
+ if (!extract_hard_forks(events, hardforks))
+ {
+ MDEBUG("Extracting hard-forks from blocks");
+ extract_hard_forks_from_blocks(events, hardforks);
+ }
+
+ hardforks.push_back(std::make_pair((uint8_t)0, (uint64_t)0)); // terminator
+ test_options_tmp.hard_forks = hardforks.data();
+ test_options = &test_options_tmp;
+
+ cryptonote::tx_memory_pool txpool(*bc);
+ bc.reset(new cryptonote::Blockchain(txpool));
+
+ cryptonote::Blockchain *blockchain = bc.get();
+ auto bdb = new TestDB();
+
+ BOOST_FOREACH(const test_event_entry &ev, events)
+ {
+ if (typeid(block) != ev.type())
+ {
+ continue;
+ }
+
+ const block *blk = &boost::get<block>(ev);
+ auto blk_hash = get_block_hash(*blk);
+ bdb->add_block(*blk, 1, 1, 1, 0, 0, blk_hash);
+ }
+
+ bool r = blockchain->init(bdb, nettype, true, test_options, 2, nullptr);
+ CHECK_AND_ASSERT_THROW_MES(r, "could not init blockchain from events");
+ return bc;
+}
void test_generator::get_block_chain(std::vector<block_info>& blockchain, const crypto::hash& head, size_t n) const
{
@@ -184,13 +310,7 @@ bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, co
//blk.tree_root_hash = get_tx_tree_hash(blk);
- // Nonce search...
- blk.nonce = 0;
- while (!miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){
- return cryptonote::get_block_longhash(NULL, b, hash, height, threads);
- }, blk, get_test_difficulty(hf_ver), height))
- blk.timestamp++;
-
+ fill_nonce(blk, get_test_difficulty(hf_ver), height);
add_block(blk, txs_weight, block_weights, already_generated_coins, hf_ver ? hf_ver.get() : 1);
return true;
@@ -268,6 +388,26 @@ bool test_generator::construct_block_manually_tx(cryptonote::block& blk, const c
return construct_block_manually(blk, prev_block, miner_acc, bf_tx_hashes, 0, 0, 0, crypto::hash(), 0, transaction(), tx_hashes, txs_weight);
}
+void test_generator::fill_nonce(cryptonote::block& blk, const difficulty_type& diffic, uint64_t height)
+{
+ const cryptonote::Blockchain *blockchain = nullptr;
+ std::unique_ptr<cryptonote::Blockchain> bc;
+
+ if (blk.major_version >= RX_BLOCK_VERSION)
+ {
+ CHECK_AND_ASSERT_THROW_MES(m_events != nullptr, "events not set, cannot compute valid RandomX PoW");
+ bc = init_blockchain(*m_events, m_nettype);
+ blockchain = bc.get();
+ }
+
+ blk.nonce = 0;
+ while (!miner::find_nonce_for_given_block([blockchain](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){
+ return cryptonote::get_block_longhash(blockchain, b, hash, height, threads);
+ }, blk, diffic, height)) {
+ blk.timestamp++;
+ }
+}
+
namespace
{
uint64_t get_inputs_amount(const vector<tx_source_entry> &s)
@@ -796,15 +936,6 @@ void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
fill_tx_sources_and_destinations(events, blk_head, from, to.get_keys().m_account_address, amount, fee, nmix, sources, destinations);
}
-void fill_nonce(cryptonote::block& blk, const difficulty_type& diffic, uint64_t height)
-{
- blk.nonce = 0;
- while (!miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){
- return cryptonote::get_block_longhash(NULL, b, hash, height, threads);
- }, blk, diffic, height))
- blk.timestamp++;
-}
-
cryptonote::tx_destination_entry build_dst(const var_addr_t& to, bool is_subaddr, uint64_t amount)
{
tx_destination_entry de;
@@ -983,6 +1114,31 @@ bool extract_hard_forks(const std::vector<test_event_entry>& events, v_hardforks
return !hard_forks.empty();
}
+bool extract_hard_forks_from_blocks(const std::vector<test_event_entry>& events, v_hardforks_t& hard_forks)
+{
+ int hf = -1;
+ int64_t height = 0;
+
+ for(auto & ev : events)
+ {
+ if (typeid(block) != ev.type())
+ {
+ continue;
+ }
+
+ const block *blk = &boost::get<block>(ev);
+ if (blk->major_version != hf)
+ {
+ hf = blk->major_version;
+ hard_forks.push_back(std::make_pair(blk->major_version, (uint64_t)height));
+ }
+
+ height += 1;
+ }
+
+ return !hard_forks.empty();
+}
+
void get_confirmed_txs(const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx, map_hash2tx_t& confirmed_txs)
{
std::unordered_set<crypto::hash> confirmed_hashes;
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index 1594d7a08..80ce7404b 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -47,6 +47,7 @@
#include "include_base_utils.h"
#include "common/boost_serialization_helper.h"
#include "common/command_line.h"
+#include "common/threadpool.h"
#include "cryptonote_basic/account_boost_serialization.h"
#include "cryptonote_basic/cryptonote_basic.h"
@@ -227,8 +228,8 @@ public:
bf_hf_version= 1 << 8
};
- test_generator() {}
- test_generator(const test_generator &other): m_blocks_info(other.m_blocks_info) {}
+ test_generator(): m_events(nullptr) {}
+ test_generator(const test_generator &other): m_blocks_info(other.m_blocks_info), m_events(other.m_events), m_nettype(other.m_nettype) {}
void get_block_chain(std::vector<block_info>& blockchain, const crypto::hash& head, size_t n) const;
void get_last_n_block_weights(std::vector<size_t>& block_weights, const crypto::hash& head, size_t n) const;
uint64_t get_already_generated_coins(const crypto::hash& blk_id) const;
@@ -253,9 +254,14 @@ public:
uint8_t hf_version = 1);
bool construct_block_manually_tx(cryptonote::block& blk, const cryptonote::block& prev_block,
const cryptonote::account_base& miner_acc, const std::vector<crypto::hash>& tx_hashes, size_t txs_size);
+ void fill_nonce(cryptonote::block& blk, const cryptonote::difficulty_type& diffic, uint64_t height);
+ void set_events(const std::vector<test_event_entry> * events) { m_events = events; }
+ void set_network_type(const cryptonote::network_type nettype) { m_nettype = nettype; }
private:
std::unordered_map<crypto::hash, block_info> m_blocks_info;
+ const std::vector<test_event_entry> * m_events;
+ cryptonote::network_type m_nettype;
friend class boost::serialization::access;
@@ -407,7 +413,6 @@ cryptonote::account_public_address get_address(const cryptonote::tx_destination_
inline cryptonote::difficulty_type get_test_difficulty(const boost::optional<uint8_t>& hf_ver=boost::none) {return !hf_ver || hf_ver.get() <= 1 ? 1 : 2;}
inline uint64_t current_difficulty_window(const boost::optional<uint8_t>& hf_ver=boost::none){ return !hf_ver || hf_ver.get() <= 1 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2; }
-void fill_nonce(cryptonote::block& blk, const cryptonote::difficulty_type& diffic, uint64_t height);
cryptonote::tx_destination_entry build_dst(const var_addr_t& to, bool is_subaddr=false, uint64_t amount=0);
std::vector<cryptonote::tx_destination_entry> build_dsts(const var_addr_t& to1, bool sub1=false, uint64_t am1=0);
@@ -490,6 +495,7 @@ void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
uint64_t get_balance(const cryptonote::account_base& addr, const std::vector<cryptonote::block>& blockchain, const map_hash2tx_t& mtx);
bool extract_hard_forks(const std::vector<test_event_entry>& events, v_hardforks_t& hard_forks);
+bool extract_hard_forks_from_blocks(const std::vector<test_event_entry>& events, v_hardforks_t& hard_forks);
/************************************************************************/
/* */
@@ -770,6 +776,7 @@ inline bool do_replay_events_get_core(std::vector<test_event_entry>& events, cry
t_test_class validator;
bool ret = replay_events_through_core<t_test_class>(c, events, validator);
+ tools::threadpool::getInstance().recycle();
// c.deinit();
return ret;
}
diff --git a/tests/core_tests/wallet_tools.cpp b/tests/core_tests/wallet_tools.cpp
index 21a9455c0..fdc4753f9 100644
--- a/tests/core_tests/wallet_tools.cpp
+++ b/tests/core_tests/wallet_tools.cpp
@@ -10,9 +10,6 @@ using namespace epee;
using namespace crypto;
using namespace cryptonote;
-// Shared random generator
-static std::default_random_engine RND(crypto::rand<unsigned>());
-
void wallet_accessor_test::set_account(tools::wallet2 * wallet, cryptonote::account_base& account)
{
wallet->clear();
diff --git a/utils/gpg_keys/binaryfate.asc b/utils/gpg_keys/binaryfate.asc
new file mode 100644
index 000000000..55c5b161c
--- /dev/null
+++ b/utils/gpg_keys/binaryfate.asc
@@ -0,0 +1,87 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+lmE0kDaYQqoBKXNXcybElBID8Q==
+=tkJZ
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/utils/gpg_keys/snipa.asc b/utils/gpg_keys/snipa.asc
new file mode 100644
index 000000000..caee18fda
--- /dev/null
+++ b/utils/gpg_keys/snipa.asc
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+nDKy8l5Mnmigd0+k1Mx+Lw==
+=ACfD
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py
index 141e6595c..703261a4e 100644
--- a/utils/python-rpc/framework/wallet.py
+++ b/utils/python-rpc/framework/wallet.py
@@ -237,14 +237,15 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(create_account)
- def create_address(self, account_index = 0, label = ""):
+ def create_address(self, account_index = 0, label = "", count = 1):
create_address = {
'method': 'create_address',
'params' : {
'account_index': account_index,
- 'label': label
+ 'label': label,
+ 'count': count
},
- 'jsonrpc': '2.0',
+ 'jsonrpc': '2.0',
'id': '0'
}
return self.rpc.send_json_rpc_request(create_address)
@@ -1063,6 +1064,20 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(stop_mining)
+ def estimate_tx_size_and_weight(self, n_inputs, n_outputs, ring_size = 0, rct = True):
+ estimate_tx_size_and_weight = {
+ 'method': 'estimate_tx_size_and_weight',
+ 'jsonrpc': '2.0',
+ 'params': {
+ 'n_inputs': n_inputs,
+ 'n_outputs': n_outputs,
+ 'ring_size': ring_size,
+ 'rct': rct,
+ },
+ 'id': '0'
+ }
+ return self.rpc.send_json_rpc_request(estimate_tx_size_and_weight)
+
def get_version(self):
get_version = {
'method': 'get_version',
diff --git a/utils/translations/build-translations.sh b/utils/translations/build-translations.sh
index 1217dca0a..c868a691f 100755
--- a/utils/translations/build-translations.sh
+++ b/utils/translations/build-translations.sh
@@ -7,6 +7,10 @@ then
fi
if test -z "$lrelease"
then
+ lrelease=`which lrelease-qt5 2> /dev/null`
+fi
+if test -z "$lrelease"
+then
echo "lrelease not found"
exit 1
fi
@@ -17,7 +21,7 @@ then
languages=""
for language in $(cat translations/ready)
do
- languages="$languages translations/$language.ts"
+ languages="$languages translations/monero_$language.ts"
done
else
languages="translations/*.ts"