aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/blockchain_db/blockchain_db.h2
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp16
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h6
-rw-r--r--src/blockchain_utilities/CMakeLists.txt6
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp63
-rw-r--r--src/blockchain_utilities/bootstrap_file.cpp100
-rw-r--r--src/blockchain_utilities/bootstrap_file.h2
-rw-r--r--src/checkpoints/CMakeLists.txt60
-rw-r--r--src/checkpoints/checkpoints.cpp (renamed from src/cryptonote_basic/checkpoints.cpp)11
-rw-r--r--src/checkpoints/checkpoints.h (renamed from src/cryptonote_basic/checkpoints.h)7
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/apply_permutation.h68
-rw-r--r--src/common/dns_utils.cpp25
-rw-r--r--src/common/util.cpp76
-rw-r--r--src/common/util.h26
-rw-r--r--src/crypto/crypto.h22
-rw-r--r--src/crypto/hash.h13
-rw-r--r--src/cryptonote_basic/CMakeLists.txt5
-rw-r--r--src/cryptonote_basic/connection_context.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h5
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h25
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp19
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h2
-rw-r--r--src/cryptonote_config.h1
-rw-r--r--src/cryptonote_core/CMakeLists.txt3
-rw-r--r--src/cryptonote_core/blockchain.cpp51
-rw-r--r--src/cryptonote_core/blockchain.h2
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp11
-rw-r--r--src/cryptonote_core/cryptonote_core.h4
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.cpp44
-rw-r--r--src/cryptonote_core/cryptonote_tx_utils.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp10
-rw-r--r--src/cryptonote_protocol/CMakeLists.txt2
-rw-r--r--src/cryptonote_protocol/block_queue.cpp2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h6
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl17
-rw-r--r--src/daemon/CMakeLists.txt2
-rw-r--r--src/daemon/command_line_args.h5
-rw-r--r--src/daemon/command_parser_executor.cpp46
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp2
-rw-r--r--src/daemon/main.cpp3
-rw-r--r--src/daemon/rpc_command_executor.cpp128
-rw-r--r--src/daemon/rpc_command_executor.h6
-rw-r--r--src/debug_utilities/CMakeLists.txt4
-rw-r--r--src/p2p/CMakeLists.txt3
-rw-r--r--src/p2p/net_node.inl2
-rw-r--r--src/p2p/net_peerlist.h21
-rw-r--r--src/rpc/CMakeLists.txt7
-rw-r--r--src/rpc/core_rpc_server.cpp155
-rw-r--r--src/rpc/core_rpc_server.h4
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h56
-rw-r--r--src/rpc/daemon_handler.cpp2
-rw-r--r--src/serialization/json_object.cpp1
-rw-r--r--src/serialization/serialization.h17
-rw-r--r--src/serialization/vector.h19
-rw-r--r--src/simplewallet/CMakeLists.txt3
-rw-r--r--src/simplewallet/simplewallet.cpp59
-rw-r--r--src/simplewallet/simplewallet.h2
-rw-r--r--src/version.cmake4
-rw-r--r--src/version.cpp.in11
-rw-r--r--src/version.h6
-rw-r--r--src/version.h.in4
-rw-r--r--src/wallet/CMakeLists.txt3
-rw-r--r--src/wallet/api/address_book.cpp6
-rw-r--r--src/wallet/api/unsigned_transaction.cpp8
-rw-r--r--src/wallet/api/wallet.cpp20
-rw-r--r--src/wallet/api/wallet.h3
-rw-r--r--src/wallet/api/wallet_manager.cpp6
-rw-r--r--src/wallet/api/wallet_manager.h2
-rw-r--r--src/wallet/wallet2.cpp468
-rw-r--r--src/wallet/wallet2.h78
-rw-r--r--src/wallet/wallet2_api.h2
-rw-r--r--src/wallet/wallet_args.cpp6
-rw-r--r--src/wallet/wallet_rpc_server.cpp78
-rw-r--r--src/wallet/wallet_rpc_server.h3
77 files changed, 1415 insertions, 563 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e3cb7cfd6..57ff28bfc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -96,9 +96,13 @@ function (monero_add_library name)
PRIVATE $<TARGET_PROPERTY:${name},INTERFACE_COMPILE_DEFINITIONS>)
endfunction ()
+set_source_files_properties(${CMAKE_BINARY_DIR}/version.cpp PROPERTIES GENERATED ON)
+monero_add_library(version ${CMAKE_BINARY_DIR}/version.cpp)
+
add_subdirectory(common)
add_subdirectory(crypto)
add_subdirectory(ringct)
+add_subdirectory(checkpoints)
add_subdirectory(cryptonote_basic)
add_subdirectory(cryptonote_core)
if(NOT IOS)
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 85a494ce7..838385e8a 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -711,7 +711,7 @@ public:
*
* @return true if we started the batch, false if already started
*/
- virtual bool batch_start(uint64_t batch_num_blocks=0) = 0;
+ virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) = 0;
/**
* @brief ends a batch transaction
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index c6e24ef98..985244f6b 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -548,7 +548,7 @@ bool BlockchainLMDB::need_resize(uint64_t threshold_size) const
#endif
}
-void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks)
+void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks, uint64_t batch_bytes)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
LOG_PRINT_L1("[" << __func__ << "] " << "checking DB size");
@@ -557,7 +557,7 @@ void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks)
uint64_t increase_size = 0;
if (batch_num_blocks > 0)
{
- threshold_size = get_estimated_batch_size(batch_num_blocks);
+ threshold_size = get_estimated_batch_size(batch_num_blocks, batch_bytes);
LOG_PRINT_L1("calculated batch size: " << threshold_size);
// The increased DB size could be a multiple of threshold_size, a fixed
@@ -580,7 +580,7 @@ void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks)
}
}
-uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) const
+uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks, uint64_t batch_bytes) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
uint64_t threshold_size = 0;
@@ -607,6 +607,11 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
uint64_t total_block_size = 0;
LOG_PRINT_L1("[" << __func__ << "] " << "m_height: " << m_height << " block_start: " << block_start << " block_stop: " << block_stop);
size_t avg_block_size = 0;
+ if (batch_bytes)
+ {
+ avg_block_size = batch_bytes / batch_num_blocks;
+ goto estim;
+ }
if (m_height == 0)
{
LOG_PRINT_L1("No existing blocks to check for average block size");
@@ -635,6 +640,7 @@ uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) con
avg_block_size = total_block_size / num_blocks_used;
LOG_PRINT_L1("average block size across recent " << num_blocks_used << " blocks: " << avg_block_size);
}
+estim:
if (avg_block_size < min_block_size)
avg_block_size = min_block_size;
LOG_PRINT_L1("estimated average block size for batch: " << avg_block_size);
@@ -2540,7 +2546,7 @@ bool BlockchainLMDB::for_all_outputs(std::function<bool(uint64_t amount, const c
}
// batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts.
-bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
+bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks, uint64_t batch_bytes)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
if (! m_batch_transactions)
@@ -2554,7 +2560,7 @@ bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks)
check_open();
m_writer = boost::this_thread::get_id();
- check_and_resize_for_batch(batch_num_blocks);
+ check_and_resize_for_batch(batch_num_blocks, batch_bytes);
m_write_batch_txn = new mdb_txn_safe();
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 90274b904..98571a7f8 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -264,7 +264,7 @@ public:
);
virtual void set_batch_transactions(bool batch_transactions);
- virtual bool batch_start(uint64_t batch_num_blocks=0);
+ virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0);
virtual void batch_commit();
virtual void batch_stop();
virtual void batch_abort();
@@ -294,8 +294,8 @@ private:
void do_resize(uint64_t size_increase=0);
bool need_resize(uint64_t threshold_size=0) const;
- void check_and_resize_for_batch(uint64_t batch_num_blocks);
- uint64_t get_estimated_batch_size(uint64_t batch_num_blocks) const;
+ void check_and_resize_for_batch(uint64_t batch_num_blocks, uint64_t batch_bytes);
+ uint64_t get_estimated_batch_size(uint64_t batch_num_blocks, uint64_t batch_bytes) const;
virtual void add_block( const block& blk
, const size_t& block_size
diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt
index ffdaad4af..0eaf71084 100644
--- a/src/blockchain_utilities/CMakeLists.txt
+++ b/src/blockchain_utilities/CMakeLists.txt
@@ -77,6 +77,7 @@ target_link_libraries(blockchain_import
cryptonote_core
blockchain_db
p2p
+ version
epee
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
@@ -89,8 +90,6 @@ if(ARCH_WIDTH)
PUBLIC -DARCH_WIDTH=${ARCH_WIDTH})
endif()
-add_dependencies(blockchain_import
- version)
set_property(TARGET blockchain_import
PROPERTY
OUTPUT_NAME "monero-blockchain-import")
@@ -104,6 +103,7 @@ target_link_libraries(blockchain_export
cryptonote_core
blockchain_db
p2p
+ version
epee
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
@@ -111,8 +111,6 @@ target_link_libraries(blockchain_export
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
-add_dependencies(blockchain_export
- version)
set_property(TARGET blockchain_export
PROPERTY
OUTPUT_NAME "monero-blockchain-export")
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 635a70b10..d6302ea1d 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -230,11 +230,22 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
return false;
}
+ uint64_t start_height = 1, seek_height;
+ if (opt_resume)
+ start_height = core.get_blockchain_storage().get_current_blockchain_height();
+
+ seek_height = start_height;
BootstrapFile bootstrap;
+ streampos pos;
// BootstrapFile bootstrap(import_file_path);
- uint64_t total_source_blocks = bootstrap.count_blocks(import_file_path);
+ uint64_t total_source_blocks = bootstrap.count_blocks(import_file_path, pos, seek_height);
MINFO("bootstrap file last block number: " << total_source_blocks-1 << " (zero-based height) total blocks: " << total_source_blocks);
+ if (total_source_blocks-1 <= start_height)
+ {
+ return false;
+ }
+
std::cout << ENDL;
std::cout << "Preparing to read blocks..." << ENDL;
std::cout << ENDL;
@@ -259,11 +270,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
block b;
transaction tx;
int quit = 0;
- uint64_t bytes_read = 0;
-
- uint64_t start_height = 1;
- if (opt_resume)
- start_height = core.get_blockchain_storage().get_current_blockchain_height();
+ uint64_t bytes_read;
// Note that a new blockchain will start with block number 0 (total blocks: 1)
// due to genesis block being added at initialization.
@@ -280,18 +287,35 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
bool use_batch = opt_batch && !opt_verify;
- if (use_batch)
- core.get_blockchain_storage().get_db().batch_start(db_batch_size);
-
MINFO("Reading blockchain from bootstrap file...");
std::cout << ENDL;
std::list<block_complete_entry> blocks;
- // Within the loop, we skip to start_height before we start adding.
- // TODO: Not a bottleneck, but we can use what's done in count_blocks() and
- // only do the chunk size reads, skipping the chunk content reads until we're
- // at start_height.
+ // Skip to start_height before we start adding.
+ {
+ bool q2 = false;
+ import_file.seekg(pos);
+ bytes_read = bootstrap.count_bytes(import_file, start_height-seek_height, h, q2);
+ if (q2)
+ {
+ quit = 2;
+ goto quitting;
+ }
+ h = start_height;
+ }
+
+ if (use_batch)
+ {
+ uint64_t bytes, h2;
+ bool q2;
+ pos = import_file.tellg();
+ bytes = bootstrap.count_bytes(import_file, db_batch_size, h2, q2);
+ if (import_file.eof())
+ import_file.clear();
+ import_file.seekg(pos);
+ core.get_blockchain_storage().get_db().batch_start(db_batch_size, bytes);
+ }
while (! quit)
{
uint32_t chunk_size;
@@ -344,11 +368,6 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
bytes_read += chunk_size;
MDEBUG("Total bytes read: " << bytes_read);
- if (h + NUM_BLOCKS_PER_CHUNK < start_height + 1)
- {
- h += NUM_BLOCKS_PER_CHUNK;
- continue;
- }
if (h > block_stop)
{
std::cout << refresh_string << "block " << h-1
@@ -456,11 +475,16 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
{
if ((h-1) % db_batch_size == 0)
{
+ uint64_t bytes, h2;
+ bool q2;
std::cout << refresh_string;
// zero-based height
std::cout << ENDL << "[- batch commit at height " << h-1 << " -]" << ENDL;
core.get_blockchain_storage().get_db().batch_stop();
- core.get_blockchain_storage().get_db().batch_start(db_batch_size);
+ pos = import_file.tellg();
+ bytes = bootstrap.count_bytes(import_file, db_batch_size, h2, q2);
+ import_file.seekg(pos);
+ core.get_blockchain_storage().get_db().batch_start(db_batch_size, bytes);
std::cout << ENDL;
core.get_blockchain_storage().get_db().show_stats();
}
@@ -477,6 +501,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
}
} // while
+quitting:
import_file.close();
if (opt_verify)
diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp
index 2b1a5d6c7..a004d3547 100644
--- a/src/blockchain_utilities/bootstrap_file.cpp
+++ b/src/blockchain_utilities/bootstrap_file.cpp
@@ -375,39 +375,15 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file)
return full_header_size;
}
-uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
+uint64_t BootstrapFile::count_bytes(std::ifstream& import_file, uint64_t blocks, uint64_t& h, bool& quit)
{
- boost::filesystem::path raw_file_path(import_file_path);
- boost::system::error_code ec;
- if (!boost::filesystem::exists(raw_file_path, ec))
- {
- MFATAL("bootstrap file not found: " << raw_file_path);
- throw std::runtime_error("Aborting");
- }
- std::ifstream import_file;
- import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in);
-
- uint64_t h = 0;
- if (import_file.fail())
- {
- MFATAL("import_file.open() fail");
- throw std::runtime_error("Aborting");
- }
-
- uint64_t full_header_size; // 4 byte magic + length of header structures
- full_header_size = seek_to_first_chunk(import_file);
-
- MINFO("Scanning blockchain from bootstrap file...");
- block b;
- bool quit = false;
uint64_t bytes_read = 0;
- int progress_interval = 10;
-
+ uint32_t chunk_size;
+ char buf1[sizeof(chunk_size)];
std::string str1;
- char buf1[2048];
- while (! quit)
+ h = 0;
+ while (1)
{
- uint32_t chunk_size;
import_file.read(buf1, sizeof(chunk_size));
if (!import_file) {
std::cout << refresh_string;
@@ -415,15 +391,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
quit = true;
break;
}
- h += NUM_BLOCKS_PER_CHUNK;
- if ((h-1) % progress_interval == 0)
- {
- std::cout << "\r" << "block height: " << h-1 <<
- " " <<
- std::flush;
- }
bytes_read += sizeof(chunk_size);
-
str1.assign(buf1, sizeof(chunk_size));
if (! ::serialization::parse_binary(str1, chunk_size))
throw std::runtime_error("Error in deserialization of chunk_size");
@@ -456,6 +424,64 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
throw std::runtime_error("Aborting");
}
bytes_read += chunk_size;
+ h += NUM_BLOCKS_PER_CHUNK;
+ if (h >= blocks)
+ break;
+ }
+ return bytes_read;
+}
+
+uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
+{
+ streampos dummy_pos;
+ uint64_t dummy_height = 0;
+ return count_blocks(import_file_path, dummy_pos, dummy_height);
+}
+
+// If seek_height is non-zero on entry, return a stream position <= this height when finished.
+// And return the actual height corresponding to this position. Allows the caller to locate its
+// starting position without having to reread the entire file again.
+uint64_t BootstrapFile::count_blocks(const std::string& import_file_path, streampos &start_pos, uint64_t& seek_height)
+{
+ boost::filesystem::path raw_file_path(import_file_path);
+ boost::system::error_code ec;
+ if (!boost::filesystem::exists(raw_file_path, ec))
+ {
+ MFATAL("bootstrap file not found: " << raw_file_path);
+ throw std::runtime_error("Aborting");
+ }
+ std::ifstream import_file;
+ import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in);
+
+ uint64_t start_height = seek_height;
+ uint64_t h = 0;
+ if (import_file.fail())
+ {
+ MFATAL("import_file.open() fail");
+ throw std::runtime_error("Aborting");
+ }
+
+ uint64_t full_header_size; // 4 byte magic + length of header structures
+ full_header_size = seek_to_first_chunk(import_file);
+
+ MINFO("Scanning blockchain from bootstrap file...");
+ bool quit = false;
+ uint64_t bytes_read = 0, blocks;
+ int progress_interval = 10;
+
+ while (! quit)
+ {
+ if (start_height && h + progress_interval >= start_height - 1)
+ {
+ start_height = 0;
+ start_pos = import_file.tellg();
+ seek_height = h;
+ }
+ bytes_read += count_bytes(import_file, progress_interval, blocks, quit);
+ h += blocks;
+ std::cout << "\r" << "block height: " << h-1 <<
+ " " <<
+ std::flush;
// std::cout << refresh_string;
MDEBUG("Number bytes scanned: " << bytes_read);
diff --git a/src/blockchain_utilities/bootstrap_file.h b/src/blockchain_utilities/bootstrap_file.h
index 1a646b54b..c3969a357 100644
--- a/src/blockchain_utilities/bootstrap_file.h
+++ b/src/blockchain_utilities/bootstrap_file.h
@@ -56,6 +56,8 @@ class BootstrapFile
{
public:
+ uint64_t count_bytes(std::ifstream& import_file, uint64_t blocks, uint64_t& h, bool& quit);
+ uint64_t count_blocks(const std::string& dir_path, streampos& start_pos, uint64_t& seek_height);
uint64_t count_blocks(const std::string& dir_path);
uint64_t seek_to_first_chunk(std::ifstream& import_file);
diff --git a/src/checkpoints/CMakeLists.txt b/src/checkpoints/CMakeLists.txt
new file mode 100644
index 000000000..bc7a27e36
--- /dev/null
+++ b/src/checkpoints/CMakeLists.txt
@@ -0,0 +1,60 @@
+# Copyright (c) 2014-2017, 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.
+
+if(APPLE)
+ find_library(IOKIT_LIBRARY IOKit)
+ mark_as_advanced(IOKIT_LIBRARY)
+ list(APPEND EXTRA_LIBRARIES ${IOKIT_LIBRARY})
+endif()
+
+set(checkpoints_sources
+ checkpoints.cpp)
+
+set(checkpoints_headers)
+
+set(checkpoints_private_headers
+ checkpoints.h)
+
+monero_private_headers(checkpoints
+ ${checkpoints_private_headers})
+monero_add_library(checkpoints
+ ${checkpoints_sources}
+ ${checkpoints_headers}
+ ${checkpoints_private_headers})
+target_link_libraries(checkpoints
+ PUBLIC
+ common
+ cncrypto
+ ${Boost_DATE_TIME_LIBRARY}
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_SERIALIZATION_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY}
+ ${Boost_SYSTEM_LIBRARY}
+ ${Boost_THREAD_LIBRARY}
+ PRIVATE
+ ${EXTRA_LIBRARIES})
diff --git a/src/cryptonote_basic/checkpoints.cpp b/src/checkpoints/checkpoints.cpp
index 98e509561..bea392db0 100644
--- a/src/cryptonote_basic/checkpoints.cpp
+++ b/src/checkpoints/checkpoints.cpp
@@ -36,6 +36,7 @@ using namespace epee;
#include "common/dns_utils.h"
#include "include_base_utils.h"
+#include "storages/portable_storage_template_helper.h" // epee json include
#include <sstream>
#include <random>
@@ -51,7 +52,7 @@ namespace cryptonote
//---------------------------------------------------------------------------
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
{
- crypto::hash h = null_hash;
+ crypto::hash h = crypto::null_hash;
bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!");
@@ -135,8 +136,14 @@ namespace cryptonote
return true;
}
- bool checkpoints::init_default_checkpoints()
+ bool checkpoints::init_default_checkpoints(bool testnet)
{
+ if (testnet)
+ {
+ // just use the genesis block on testnet
+ ADD_CHECKPOINT(0, "48ca7cd3c8de5b6a4d53d2861fbdaedca141553559f9be9520068053cda8430b");
+ return true;
+ }
ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148");
ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381");
ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d");
diff --git a/src/cryptonote_basic/checkpoints.h b/src/checkpoints/checkpoints.h
index 3a74d8a69..a643c5790 100644
--- a/src/cryptonote_basic/checkpoints.h
+++ b/src/checkpoints/checkpoints.h
@@ -31,9 +31,9 @@
#pragma once
#include <map>
#include <vector>
-#include "cryptonote_basic_impl.h"
#include "misc_log_ex.h"
-#include "storages/portable_storage_template_helper.h" // epee json include
+#include "crypto/hash.h"
+#include "serialization/keyvalue_serialization.h"
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false);
#define JSON_HASH_FILE_NAME "checkpoints.json"
@@ -148,10 +148,11 @@ namespace cryptonote
/**
* @brief loads the default main chain checkpoints
+ * @param testnet whether to load testnet checkpoints or mainnet
*
* @return true unless adding a checkpoint fails
*/
- bool init_default_checkpoints();
+ bool init_default_checkpoints(bool testnet);
/**
* @brief load new checkpoints
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 19d90253b..50887e35c 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -47,6 +47,7 @@ endif()
set(common_headers)
set(common_private_headers
+ apply_permutation.h
base58.h
boost_serialization_helper.h
command_line.h
diff --git a/src/common/apply_permutation.h b/src/common/apply_permutation.h
new file mode 100644
index 000000000..4fd952686
--- /dev/null
+++ b/src/common/apply_permutation.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2017, 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.
+//
+// Most of this file is originally copyright (c) 2017 Raymond Chen, Microsoft
+// This algorithm is adapted from Raymond Chen's code:
+// https://blogs.msdn.microsoft.com/oldnewthing/20170109-00/?p=95145
+
+#include <vector>
+#include <functional>
+#include "misc_log_ex.h"
+
+namespace tools
+{
+
+template<typename F>
+void apply_permutation(std::vector<size_t> permutation, const F &swap)
+{
+ //sanity check
+ for (size_t n = 0; n < permutation.size(); ++n)
+ CHECK_AND_ASSERT_THROW_MES(std::find(permutation.begin(), permutation.end(), n) != permutation.end(), "Bad permutation");
+
+ for (size_t i = 0; i < permutation.size(); ++i)
+ {
+ size_t current = i;
+ while (i != permutation[current])
+ {
+ size_t next = permutation[current];
+ swap(current, next);
+ permutation[current] = current;
+ current = next;
+ }
+ permutation[current] = current;
+ }
+}
+
+template<typename T>
+void apply_permutation(const std::vector<size_t> &permutation, std::vector<T> &v)
+{
+ CHECK_AND_ASSERT_THROW_MES(permutation.size() == v.size(), "Mismatched vector sizes");
+ apply_permutation(permutation, [&v](size_t i0, size_t i1){ std::swap(v[i0], v[i1]); });
+}
+
+}
diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp
index e7ff11c5c..1310b8bfd 100644
--- a/src/common/dns_utils.cpp
+++ b/src/common/dns_utils.cpp
@@ -27,8 +27,6 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "common/dns_utils.h"
-#include "common/i18n.h"
-#include "cryptonote_basic/cryptonote_basic_impl.h"
// check local first (in the event of static or in-source compilation of libunbound)
#include "unbound.h"
@@ -326,8 +324,6 @@ bool DNSResolver::check_address_syntax(const char *addr) const
namespace dns_utils
{
-const char *tr(const char *str) { return i18n_translate(str, "tools::dns_utils"); }
-
//-----------------------------------------------------------------------
// TODO: parse the string in a less stupid way, probably with regex
std::string address_from_txt_record(const std::string& s)
@@ -447,19 +443,28 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std
std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1);
size_t first_index = dis(gen);
- bool avail, valid;
+ // send all requests in parallel
+ std::vector<boost::thread> threads(dns_urls.size());
+ std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false);
+ for (size_t n = 0; n < dns_urls.size(); ++n)
+ {
+ threads[n] = boost::thread([n, dns_urls, &records, &avail, &valid](){
+ records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]);
+ });
+ }
+ for (size_t n = 0; n < dns_urls.size(); ++n)
+ threads[n].join();
+
size_t cur_index = first_index;
do
{
- std::string url = dns_urls[cur_index];
-
- records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid);
- if (!avail)
+ const std::string &url = dns_urls[cur_index];
+ if (!avail[cur_index])
{
records[cur_index].clear();
LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping.");
}
- if (!valid)
+ if (!valid[cur_index])
{
records[cur_index].clear();
LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping.");
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 046961b06..74a6babf1 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -39,11 +39,13 @@ using namespace epee;
#include "net/http_client.h" // epee::net_utils::...
#ifdef WIN32
-#include <windows.h>
-#include <shlobj.h>
-#include <strsafe.h>
+ #include <windows.h>
+ #include <shlobj.h>
+ #include <strsafe.h>
#else
-#include <sys/utsname.h>
+ #include <sys/file.h>
+ #include <sys/utsname.h>
+ #include <sys/stat.h>
#endif
#include <boost/filesystem.hpp>
#include <boost/asio.hpp>
@@ -53,7 +55,12 @@ namespace tools
{
std::function<void(int)> signal_handler::m_handler;
- std::unique_ptr<std::FILE, tools::close_file> create_private_file(const std::string& name)
+ private_file::private_file() noexcept : m_handle(), m_filename() {}
+
+ private_file::private_file(std::FILE* handle, std::string&& filename) noexcept
+ : m_handle(handle), m_filename(std::move(filename)) {}
+
+ private_file private_file::create(std::string name)
{
#ifdef WIN32
struct close_handle
@@ -70,17 +77,17 @@ namespace tools
const bool fail = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, std::addressof(temp)) == 0;
process.reset(temp);
if (fail)
- return nullptr;
+ return {};
}
DWORD sid_size = 0;
GetTokenInformation(process.get(), TokenOwner, nullptr, 0, std::addressof(sid_size));
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return nullptr;
+ return {};
std::unique_ptr<char[]> sid{new char[sid_size]};
if (!GetTokenInformation(process.get(), TokenOwner, sid.get(), sid_size, std::addressof(sid_size)))
- return nullptr;
+ return {};
const PSID psid = reinterpret_cast<const PTOKEN_OWNER>(sid.get())->Owner;
const DWORD daclSize =
@@ -88,17 +95,17 @@ namespace tools
const std::unique_ptr<char[]> dacl{new char[daclSize]};
if (!InitializeAcl(reinterpret_cast<PACL>(dacl.get()), daclSize, ACL_REVISION))
- return nullptr;
+ return {};
if (!AddAccessAllowedAce(reinterpret_cast<PACL>(dacl.get()), ACL_REVISION, (READ_CONTROL | FILE_GENERIC_READ | DELETE), psid))
- return nullptr;
+ return {};
SECURITY_DESCRIPTOR descriptor{};
if (!InitializeSecurityDescriptor(std::addressof(descriptor), SECURITY_DESCRIPTOR_REVISION))
- return nullptr;
+ return {};
if (!SetSecurityDescriptorDacl(std::addressof(descriptor), true, reinterpret_cast<PACL>(dacl.get()), false))
- return nullptr;
+ return {};
SECURITY_ATTRIBUTES attributes{sizeof(SECURITY_ATTRIBUTES), std::addressof(descriptor), false};
std::unique_ptr<void, close_handle> file{
@@ -106,7 +113,7 @@ namespace tools
name.c_str(),
GENERIC_WRITE, FILE_SHARE_READ,
std::addressof(attributes),
- CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
+ CREATE_NEW, (FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE),
nullptr
)
};
@@ -121,22 +128,49 @@ namespace tools
{
_close(fd);
}
- return {real_file, tools::close_file{}};
+ return {real_file, std::move(name)};
}
}
#else
- const int fd = open(name.c_str(), (O_RDWR | O_EXCL | O_CREAT), S_IRUSR);
- if (0 <= fd)
+ const int fdr = open(name.c_str(), (O_RDONLY | O_CREAT), S_IRUSR);
+ if (0 <= fdr)
{
- std::FILE* file = fdopen(fd, "w");
- if (!file)
+ struct stat rstats = {};
+ if (fstat(fdr, std::addressof(rstats)) != 0)
{
- close(fd);
+ close(fdr);
+ return {};
+ }
+ fchmod(fdr, (S_IRUSR | S_IWUSR));
+ const int fdw = open(name.c_str(), O_RDWR);
+ fchmod(fdr, rstats.st_mode);
+ close(fdr);
+
+ if (0 <= fdw)
+ {
+ struct stat wstats = {};
+ if (fstat(fdw, std::addressof(wstats)) == 0 &&
+ rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino &&
+ flock(fdw, (LOCK_EX | LOCK_NB)) == 0 && ftruncate(fdw, 0) == 0)
+ {
+ std::FILE* file = fdopen(fdw, "w");
+ if (file) return {file, std::move(name)};
+ }
+ close(fdw);
}
- return {file, tools::close_file{}};
}
#endif
- return nullptr;
+ return {};
+ }
+
+ private_file::~private_file() noexcept
+ {
+ try
+ {
+ boost::system::error_code ec{};
+ boost::filesystem::remove(filename(), ec);
+ }
+ catch (...) {}
}
#ifdef WIN32
diff --git a/src/common/util.h b/src/common/util.h
index 2452bc9d5..48bdbbc28 100644
--- a/src/common/util.h
+++ b/src/common/util.h
@@ -60,8 +60,30 @@ namespace tools
}
};
- //! \return File only readable by owner. nullptr if `filename` exists.
- std::unique_ptr<std::FILE, close_file> create_private_file(const std::string& filename);
+ //! A file restricted to process owner AND process. Deletes file on destruction.
+ class private_file {
+ std::unique_ptr<std::FILE, close_file> m_handle;
+ std::string m_filename;
+
+ private_file(std::FILE* handle, std::string&& filename) noexcept;
+ public:
+
+ //! `handle() == nullptr && filename.empty()`.
+ private_file() noexcept;
+
+ /*! \return File only readable by owner and only used by this process
+ OR `private_file{}` on error. */
+ static private_file create(std::string filename);
+
+ private_file(private_file&&) = default;
+ private_file& operator=(private_file&&) = default;
+
+ //! Deletes `filename()` and closes `handle()`.
+ ~private_file() noexcept;
+
+ std::FILE* handle() const noexcept { return m_handle.get(); }
+ const std::string& filename() const noexcept { return m_filename; }
+ };
/*! \brief Returns the default data directory.
*
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index e99b6651f..94f924296 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -31,12 +31,16 @@
#pragma once
#include <cstddef>
+#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
+#include <boost/utility/value_init.hpp>
#include <vector>
#include "common/pod-class.h"
#include "generic-ops.h"
+#include "hex.h"
+#include "span.h"
#include "hash.h"
namespace crypto {
@@ -248,6 +252,24 @@ namespace crypto {
const signature *sig) {
return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig);
}
+
+ inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+
+ const static crypto::public_key null_pkey = boost::value_initialized<crypto::public_key>();
}
CRYPTO_MAKE_HASHABLE(public_key)
diff --git a/src/crypto/hash.h b/src/crypto/hash.h
index 22991e513..610b4502f 100644
--- a/src/crypto/hash.h
+++ b/src/crypto/hash.h
@@ -31,9 +31,13 @@
#pragma once
#include <stddef.h>
+#include <iostream>
+#include <boost/utility/value_init.hpp>
#include "common/pod-class.h"
#include "generic-ops.h"
+#include "hex.h"
+#include "span.h"
namespace crypto {
@@ -75,6 +79,15 @@ namespace crypto {
tree_hash(reinterpret_cast<const char (*)[HASH_SIZE]>(hashes), count, reinterpret_cast<char *>(&root_hash));
}
+ inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) {
+ epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
+ }
+
+ const static crypto::hash null_hash = boost::value_initialized<crypto::hash>();
+ const static crypto::hash8 null_hash8 = boost::value_initialized<crypto::hash8>();
}
CRYPTO_MAKE_HASHABLE(hash)
diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt
index 1503b277e..750be69f1 100644
--- a/src/cryptonote_basic/CMakeLists.txt
+++ b/src/cryptonote_basic/CMakeLists.txt
@@ -34,7 +34,6 @@ endif()
set(cryptonote_basic_sources
account.cpp
- checkpoints.cpp
cryptonote_basic_impl.cpp
cryptonote_format_utils.cpp
difficulty.cpp
@@ -46,7 +45,6 @@ set(cryptonote_basic_headers)
set(cryptonote_basic_private_headers
account.h
account_boost_serialization.h
- checkpoints.h
connection_context.h
cryptonote_basic.h
cryptonote_basic_impl.h
@@ -60,7 +58,7 @@ set(cryptonote_basic_private_headers
verification_context.h)
monero_private_headers(cryptonote_basic
- ${crypto_private_headers})
+ ${cryptonote_basic_private_headers})
monero_add_library(cryptonote_basic
${cryptonote_basic_sources}
${cryptonote_basic_headers}
@@ -69,6 +67,7 @@ target_link_libraries(cryptonote_basic
PUBLIC
common
cncrypto
+ checkpoints
${Boost_DATE_TIME_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
index 3283543e2..da4b6512e 100644
--- a/src/cryptonote_basic/connection_context.h
+++ b/src/cryptonote_basic/connection_context.h
@@ -40,7 +40,7 @@ namespace cryptonote
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
{
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
- m_last_known_hash(cryptonote::null_hash) {}
+ m_last_known_hash(crypto::null_hash) {}
enum state
{
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index c4adf1fcb..eb03d33b9 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -53,11 +53,6 @@
namespace cryptonote
{
-
- const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
- const static crypto::hash8 null_hash8 = AUTO_VAL_INIT(null_hash8);
- const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey);
-
typedef std::vector<crypto::signature> ring_signature;
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index 7a2259b32..5523846d6 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -33,8 +33,6 @@
#include "cryptonote_basic.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
-#include "hex.h"
-#include "span.h"
namespace cryptonote {
@@ -136,26 +134,3 @@ namespace cryptonote {
bool parse_hash256(const std::string str_hash, crypto::hash& hash);
-namespace crypto {
- inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
- epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
- }
- inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
- epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
- }
- inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
- epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
- }
- inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
- epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
- }
- inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
- epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
- }
- inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) {
- epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
- }
- inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) {
- epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
- }
-}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 745dfb72e..fc979f288 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -632,7 +632,7 @@ namespace cryptonote
// prunable rct
if (t.rct_signatures.type == rct::RCTTypeNull)
{
- hashes[2] = cryptonote::null_hash;
+ hashes[2] = crypto::null_hash;
}
else
{
@@ -869,4 +869,21 @@ namespace cryptonote
block_hashes_calculated = block_hashes_calculated_count;
block_hashes_cached = block_hashes_cached_count;
}
+ //---------------------------------------------------------------
+ crypto::secret_key encrypt_key(const crypto::secret_key &key, const std::string &passphrase)
+ {
+ crypto::hash hash;
+ crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash);
+ sc_add((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data);
+ return key;
+ }
+ //---------------------------------------------------------------
+ crypto::secret_key decrypt_key(const crypto::secret_key &key, const std::string &passphrase)
+ {
+ crypto::hash hash;
+ crypto::cn_slow_hash(passphrase.data(), passphrase.size(), hash);
+ sc_sub((unsigned char*)key.data, (const unsigned char*)key.data, (const unsigned char*)hash.data);
+ return key;
+ }
+
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index d8ccf8eec..00080fb98 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -212,6 +212,8 @@ namespace cryptonote
bool is_valid_decomposed_amount(uint64_t amount);
void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached);
+ crypto::secret_key encrypt_key(const crypto::secret_key &key, const std::string &passphrase);
+ crypto::secret_key decrypt_key(const crypto::secret_key &key, const std::string &passphrase);
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \
CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \
specific_type& variable_name = boost::get<specific_type>(variant_var);
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index cdb46dda9..a143c307f 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -91,7 +91,6 @@
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading
-#define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT 3 //value of hop, after which we use only announce of new block
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME 86400 //seconds, one day
#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week
diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt
index 7c43323d4..169a38f0a 100644
--- a/src/cryptonote_core/CMakeLists.txt
+++ b/src/cryptonote_core/CMakeLists.txt
@@ -48,13 +48,14 @@ else()
endif()
monero_private_headers(cryptonote_core
- ${crypto_private_headers})
+ ${cryptonote_core_private_headers})
monero_add_library(cryptonote_core
${cryptonote_core_sources}
${cryptonote_core_headers}
${cryptonote_core_private_headers})
target_link_libraries(cryptonote_core
PUBLIC
+ version
common
cncrypto
blockchain_db
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 274c8cd07..0b09d503c 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -49,7 +49,6 @@
#include "common/boost_serialization_helper.h"
#include "warnings.h"
#include "crypto/hash.h"
-#include "cryptonote_basic/checkpoints.h"
#include "cryptonote_core.h"
#include "ringct/rctSigs.h"
#include "common/perf_timer.h"
@@ -2384,6 +2383,26 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
}
}
+ // from v7, sorted outs
+ if (m_hardfork->get_current_version() >= 7) {
+ const crypto::public_key *last_key = NULL;
+ for (size_t n = 0; n < tx.vout.size(); ++n)
+ {
+ const tx_out &o = tx.vout[n];
+ if (o.target.type() == typeid(txout_to_key))
+ {
+ const txout_to_key& out_to_key = boost::get<txout_to_key>(o.target);
+ if (last_key && memcmp(&out_to_key.key, last_key, sizeof(*last_key)) >= 0)
+ {
+ MERROR_VER("transaction has unsorted outputs");
+ tvc.m_invalid_output = true;
+ return false;
+ }
+ last_key = &out_to_key.key;
+ }
+ }
+ }
+
return true;
}
//------------------------------------------------------------------
@@ -2552,6 +2571,25 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
+ // from v7, sorted ins
+ if (hf_version >= 7) {
+ const crypto::key_image *last_key_image = NULL;
+ for (size_t n = 0; n < tx.vin.size(); ++n)
+ {
+ const txin_v &txin = tx.vin[n];
+ if (txin.type() == typeid(txin_to_key))
+ {
+ const txin_to_key& in_to_key = boost::get<txin_to_key>(txin);
+ if (last_key_image && memcmp(&in_to_key.k_image, last_key_image, sizeof(*last_key_image)) >= 0)
+ {
+ MERROR_VER("transaction has unsorted inputs");
+ tvc.m_verifivation_failed = true;
+ return false;
+ }
+ last_key_image = &in_to_key.k_image;
+ }
+ }
+ }
auto it = m_check_txin_table.find(tx_prefix_hash);
if(it == m_check_txin_table.end())
{
@@ -3693,6 +3731,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
MTRACE("Blockchain::" << __func__);
TIME_MEASURE_START(prepare);
bool stop_batch;
+ uint64_t bytes = 0;
// Order of locking must be:
// m_incoming_tx_lock (optional)
@@ -3714,7 +3753,15 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
if(blocks_entry.size() == 0)
return false;
- while (!(stop_batch = m_db->batch_start(blocks_entry.size()))) {
+ for (const auto &entry : blocks_entry)
+ {
+ bytes += entry.block.size();
+ for (const auto &tx_blob : entry.txs)
+ {
+ bytes += tx_blob.size();
+ }
+ }
+ while (!(stop_batch = m_db->batch_start(blocks_entry.size(), bytes))) {
m_blockchain_lock.unlock();
m_tx_pool.unlock();
epee::misc_utils::sleep_no_w(1000);
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index e2da535cd..00b40d0ad 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -51,7 +51,7 @@
#include "cryptonote_tx_utils.h"
#include "cryptonote_basic/verification_context.h"
#include "crypto/hash.h"
-#include "cryptonote_basic/checkpoints.h"
+#include "checkpoints/checkpoints.h"
#include "cryptonote_basic/hardfork.h"
#include "blockchain_db/blockchain_db.h"
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 56485aedf..c1a5ae324 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -45,7 +45,7 @@ using namespace epee;
#include "misc_language.h"
#include <csignal>
#include <p2p/net_node.h>
-#include "cryptonote_basic/checkpoints.h"
+#include "checkpoints/checkpoints.h"
#include "ringct/rctTypes.h"
#include "blockchain_db/blockchain_db.h"
#include "ringct/rctSigs.h"
@@ -183,7 +183,7 @@ namespace cryptonote
if (!m_testnet && !m_fakechain)
{
cryptonote::checkpoints checkpoints;
- if (!checkpoints.init_default_checkpoints())
+ if (!checkpoints.init_default_checkpoints(m_testnet))
{
throw std::runtime_error("Failed to initialize checkpoints");
}
@@ -211,10 +211,9 @@ namespace cryptonote
return m_blockchain_storage.get_current_blockchain_height();
}
//-----------------------------------------------------------------------------------------------
- bool core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) const
+ void core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) const
{
top_id = m_blockchain_storage.get_tail_id(height);
- return true;
}
//-----------------------------------------------------------------------------------------------
bool core::get_blocks(uint64_t start_offset, size_t count, std::list<std::pair<cryptonote::blobdata,block>>& blocks, std::list<cryptonote::blobdata>& txs) const
@@ -1041,7 +1040,6 @@ namespace cryptonote
{
cryptonote_connection_context exclude_context = boost::value_initialized<cryptonote_connection_context>();
NOTIFY_NEW_BLOCK::request arg = AUTO_VAL_INIT(arg);
- arg.hop = 0;
arg.current_blockchain_height = m_blockchain_storage.get_current_blockchain_height();
std::list<crypto::hash> missed_txs;
std::list<cryptonote::blobdata> txs;
@@ -1300,11 +1298,12 @@ namespace cryptonote
bool core::check_updates()
{
static const char software[] = "monero";
- static const char subdir[] = "cli"; // because it can never be simple
#ifdef BUILD_TAG
static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG);
+ static const char subdir[] = "cli"; // because it can never be simple
#else
static const char buildtag[] = "source";
+ static const char subdir[] = "source"; // because it can never be simple
#endif
if (check_updates_level == UPDATES_DISABLED)
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 4ea33dbe1..1aed86b25 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -299,10 +299,8 @@ namespace cryptonote
*
* @param height return-by-reference height of the block
* @param top_id return-by-reference hash of the block
- *
- * @return true
*/
- bool get_blockchain_top(uint64_t& height, crypto::hash& top_id) const;
+ void get_blockchain_top(uint64_t& height, crypto::hash& top_id) const;
/**
* @copydoc Blockchain::get_blocks(uint64_t, size_t, std::list<std::pair<cryptonote::blobdata,block>>&, std::list<transaction>&) const
diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp
index 94f069827..19ed57aba 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.cpp
+++ b/src/cryptonote_core/cryptonote_tx_utils.cpp
@@ -31,6 +31,7 @@
#include "include_base_utils.h"
using namespace epee;
+#include "common/apply_permutation.h"
#include "cryptonote_tx_utils.h"
#include "cryptonote_config.h"
#include "cryptonote_basic/miner.h"
@@ -156,7 +157,7 @@ namespace cryptonote
return destinations[0].addr.m_view_public_key;
}
//---------------------------------------------------------------
- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct)
+ bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, std::vector<tx_source_entry> sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct)
{
std::vector<rct::key> amount_keys;
tx.set_null();
@@ -263,14 +264,25 @@ namespace cryptonote
tx.vin.push_back(input_to_key);
}
- // "Shuffle" outs
- std::vector<tx_destination_entry> shuffled_dsts(destinations);
- std::random_shuffle(shuffled_dsts.begin(), shuffled_dsts.end(), [](unsigned int i) { return crypto::rand<unsigned int>() % i; });
+ // sort ins by their key image
+ std::vector<size_t> ins_order(sources.size());
+ for (size_t n = 0; n < sources.size(); ++n)
+ ins_order[n] = n;
+ std::sort(ins_order.begin(), ins_order.end(), [&](const size_t i0, const size_t i1) {
+ const txin_to_key &tk0 = boost::get<txin_to_key>(tx.vin[i0]);
+ const txin_to_key &tk1 = boost::get<txin_to_key>(tx.vin[i1]);
+ return memcmp(&tk0.k_image, &tk1.k_image, sizeof(tk0.k_image)) < 0;
+ });
+ tools::apply_permutation(ins_order, [&] (size_t i0, size_t i1) {
+ std::swap(tx.vin[i0], tx.vin[i1]);
+ std::swap(in_contexts[i0], in_contexts[i1]);
+ std::swap(sources[i0], sources[i1]);
+ });
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
- for(const tx_destination_entry& dst_entr: shuffled_dsts)
+ for(const tx_destination_entry& dst_entr: destinations)
{
CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount);
crypto::key_derivation derivation;
@@ -297,6 +309,23 @@ namespace cryptonote
summary_outs_money += dst_entr.amount;
}
+#if 0
+ // sort outs by their public key
+ std::vector<size_t> outs_order(tx.vout.size());
+ for (size_t n = 0; n < tx.vout.size(); ++n)
+ outs_order[n] = n;
+ std::sort(outs_order.begin(), outs_order.end(), [&](size_t i0, size_t i1) {
+ const txout_to_key &tk0 = boost::get<txout_to_key>(tx.vout[i0].target);
+ const txout_to_key &tk1 = boost::get<txout_to_key>(tx.vout[i1].target);
+ return memcmp(&tk0.key, &tk1.key, sizeof(tk0.key)) < 0;
+ });
+ tools::apply_permutation(outs_order, [&] (size_t i0, size_t i1) {
+ std::swap(tx.vout[i0], tx.vout[i1]);
+ if (!amount_keys.empty())
+ std::swap(amount_keys[i0], amount_keys[i1]);
+ });
+#endif
+
//check money
if(summary_outs_money > summary_inputs_money )
{
@@ -484,8 +513,9 @@ namespace cryptonote
std::string genesis_coinbase_tx_hex = config::GENESIS_TX;
blobdata tx_bl;
- string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl);
- bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx);
+ bool r = string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl);
+ CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
+ r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx);
CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob");
bl.major_version = CURRENT_BLOCK_MAJOR_VERSION;
bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h
index 7aa7c280d..69254fb5f 100644
--- a/src/cryptonote_core/cryptonote_tx_utils.h
+++ b/src/cryptonote_core/cryptonote_tx_utils.h
@@ -71,7 +71,7 @@ namespace cryptonote
//---------------------------------------------------------------
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const account_keys &sender_keys);
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time);
- bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct = false);
+ bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, std::vector<tx_source_entry> sources, const std::vector<tx_destination_entry>& destinations, std::vector<uint8_t> extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, bool rct = false);
bool generate_genesis_block(
block& bl
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index c31441a99..9071c330c 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -202,6 +202,9 @@ namespace cryptonote
return false;
}
+ // assume failure during verification steps until success is certain
+ tvc.m_verifivation_failed = true;
+
time_t receive_time = time(nullptr);
crypto::hash max_used_block_id = null_hash;
@@ -246,6 +249,7 @@ namespace cryptonote
{
LOG_PRINT_L1("tx used wrong inputs, rejected");
tvc.m_verifivation_failed = true;
+ tvc.m_invalid_input = true;
return false;
}
}else
@@ -285,9 +289,6 @@ namespace cryptonote
tvc.m_should_be_relayed = true;
}
- // assume failure during verification steps until success is certain
- tvc.m_verifivation_failed = true;
-
tvc.m_verifivation_failed = false;
MINFO("Transaction added to pool: txid " << id << " bytes: " << blob_size << " fee/byte: " << (fee / (double)blob_size));
@@ -298,7 +299,8 @@ namespace cryptonote
{
crypto::hash h = null_hash;
size_t blob_size = 0;
- get_transaction_hash(tx, h, blob_size);
+ if (!get_transaction_hash(tx, h, blob_size) || blob_size == 0)
+ return false;
return add_tx(tx, h, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version);
}
//---------------------------------------------------------------------------------
diff --git a/src/cryptonote_protocol/CMakeLists.txt b/src/cryptonote_protocol/CMakeLists.txt
index 4ce380a48..347e48eee 100644
--- a/src/cryptonote_protocol/CMakeLists.txt
+++ b/src/cryptonote_protocol/CMakeLists.txt
@@ -39,5 +39,3 @@ target_link_libraries(cryptonote_protocol
p2p
PRIVATE
${EXTRA_LIBRARIES})
-add_dependencies(cryptonote_protocol
- version)
diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp
index 02a8e3ec2..64dd1fb50 100644
--- a/src/cryptonote_protocol/block_queue.cpp
+++ b/src/cryptonote_protocol/block_queue.cpp
@@ -340,7 +340,7 @@ size_t block_queue::get_num_filled_spans() const
crypto::hash block_queue::get_last_known_hash(const boost::uuids::uuid &connection_id) const
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
- crypto::hash hash = cryptonote::null_hash;
+ crypto::hash hash = crypto::null_hash;
uint64_t highest_height = 0;
for (const auto &span: blocks)
{
diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h
index 71e205c23..1804cc101 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_defs.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h
@@ -128,12 +128,10 @@ namespace cryptonote
{
block_complete_entry b;
uint64_t current_blockchain_height;
- uint32_t hop;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(b)
KV_SERIALIZE(current_blockchain_height)
- KV_SERIALIZE(hop)
END_KV_SERIALIZE_MAP()
};
};
@@ -254,12 +252,10 @@ namespace cryptonote
{
block_complete_entry b;
uint64_t current_blockchain_height;
- uint32_t hop;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(b)
KV_SERIALIZE(current_blockchain_height)
- KV_SERIALIZE(hop)
END_KV_SERIALIZE_MAP()
};
};
@@ -276,13 +272,11 @@ namespace cryptonote
crypto::hash block_hash;
uint64_t current_blockchain_height;
std::vector<size_t> missing_tx_indices;
- uint32_t hop;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_VAL_POD_AS_BLOB(block_hash)
KV_SERIALIZE(current_blockchain_height)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(missing_tx_indices)
- KV_SERIALIZE(hop)
END_KV_SERIALIZE_MAP()
};
};
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 803d948cc..58e5fc380 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -336,7 +336,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_BLOCK (" << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
@@ -379,7 +379,6 @@ namespace cryptonote
}
if(bvc.m_added_to_main_chain)
{
- ++arg.hop;
//TODO: Add here announce protocol usage
relay_block(arg, context);
}else if(bvc.m_marked_as_orphaned)
@@ -397,7 +396,7 @@ namespace cryptonote
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context)
{
- MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", hop " << arg.hop << ", " << arg.b.txs.size() << " txes)");
+ MLOG_P2P_MESSAGE("Received NOTIFY_NEW_FLUFFY_BLOCK (height " << arg.current_blockchain_height << ", " << arg.b.txs.size() << " txes)");
if(context.m_state != cryptonote_connection_context::state_normal)
return 1;
if(!is_synchronized()) // can happen if a peer connection goes to normal but another thread still hasn't finished adding queued blocks
@@ -607,7 +606,6 @@ namespace cryptonote
MDEBUG(" tx " << new_block.tx_hashes[txidx]);
NOTIFY_REQUEST_FLUFFY_MISSING_TX::request missing_tx_req;
missing_tx_req.block_hash = get_block_hash(new_block);
- missing_tx_req.hop = arg.hop;
missing_tx_req.current_blockchain_height = arg.current_blockchain_height;
missing_tx_req.missing_tx_indices = std::move(need_tx_indices);
@@ -644,10 +642,8 @@ namespace cryptonote
}
if( bvc.m_added_to_main_chain )
{
- ++arg.hop;
//TODO: Add here announce protocol usage
NOTIFY_NEW_BLOCK::request reg_arg = AUTO_VAL_INIT(reg_arg);
- reg_arg.hop = arg.hop;
reg_arg.current_blockchain_height = arg.current_blockchain_height;
reg_arg.b = b;
relay_block(reg_arg, context);
@@ -700,7 +696,6 @@ namespace cryptonote
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
fluffy_response.b.block = t_serializable_object_to_blob(b);
fluffy_response.current_blockchain_height = arg.current_blockchain_height;
- fluffy_response.hop = arg.hop;
for(auto& tx_idx: arg.missing_tx_indices)
{
if(tx_idx < b.tx_hashes.size())
@@ -936,7 +931,8 @@ namespace cryptonote
}
// get the last parsed block, which should be the highest one
- if(m_core.have_block(cryptonote::get_block_hash(b)))
+ const crypto::hash last_block_hash = cryptonote::get_block_hash(b);
+ if(m_core.have_block(last_block_hash))
{
const uint64_t subchain_height = start_height + arg.blocks.size();
LOG_DEBUG_CC(context, "These are old blocks, ignoring: blocks " << start_height << " - " << (subchain_height-1) << ", blockchain height " << m_core.get_current_blockchain_height());
@@ -954,7 +950,7 @@ namespace cryptonote
MDEBUG(context << " adding span: " << arg.blocks.size() << " at height " << start_height << ", " << dt.total_microseconds()/1e6 << " seconds, " << (rate/1e3) << " kB/s, size now " << (m_block_queue.get_data_size() + blocks_size) / 1048576.f << " MB");
m_block_queue.add_blocks(start_height, arg.blocks, context.m_connection_id, rate, blocks_size);
- context.m_last_known_hash = cryptonote::get_blob_hash(arg.blocks.back().block);
+ context.m_last_known_hash = last_block_hash;
if (!m_core.get_test_drop_download() || !m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing
return 1;
@@ -1488,7 +1484,7 @@ skip:
if (!start_from_current_chain)
{
// we'll want to start off from where we are on that peer, which may not be added yet
- if (context.m_last_known_hash != cryptonote::null_hash && r.block_ids.front() != context.m_last_known_hash)
+ if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
r.block_ids.push_front(context.m_last_known_hash);
}
@@ -1605,7 +1601,6 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::relay_block(NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& exclude_context)
{
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_arg = AUTO_VAL_INIT(fluffy_arg);
- fluffy_arg.hop = arg.hop;
fluffy_arg.current_blockchain_height = arg.current_blockchain_height;
std::list<blobdata> fluffy_txs;
fluffy_arg.b = arg.b;
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index 782667867..d0fc1d846 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -94,6 +94,7 @@ target_link_libraries(daemon
daemonizer
serialization
daemon_rpc_server
+ version
${Boost_CHRONO_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
@@ -102,7 +103,6 @@ target_link_libraries(daemon
${CMAKE_THREAD_LIBS_INIT}
${ZMQ_LIB}
${EXTRA_LIBRARIES})
-add_dependencies(daemon version)
set_property(TARGET daemon
PROPERTY
OUTPUT_NAME "monerod")
diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h
index f19d5cc63..7fa58f9d8 100644
--- a/src/daemon/command_line_args.h
+++ b/src/daemon/command_line_args.h
@@ -46,6 +46,11 @@ namespace daemon_args
, "Specify log file"
, ""
};
+ const command_line::arg_descriptor<std::size_t> arg_max_log_file_size = {
+ "max-log-file-size"
+ , "Specify maximum log file size [B]"
+ , MAX_LOG_FILE_SIZE
+ };
const command_line::arg_descriptor<std::string> arg_log_level = {
"log-level"
, ""
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index d949a57b1..af46453cd 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -125,12 +125,17 @@ bool t_command_parser_executor::print_blockchain_info(const std::vector<std::str
bool t_command_parser_executor::set_log_level(const std::vector<std::string>& args)
{
- if(args.size() != 1)
+ if(args.size() > 1)
{
std::cout << "use: set_log [<log_level_number_0-4> | <categories>]" << std::endl;
return true;
}
+ if (args.empty())
+ {
+ return m_executor.set_log_categories("+");
+ }
+
uint16_t l = 0;
if(epee::string_tools::get_xtype_from_string(l, args[0]))
{
@@ -334,17 +339,18 @@ bool t_command_parser_executor::set_limit(const std::vector<std::string>& args)
if(args.size()==0) {
return m_executor.get_limit();
}
- int limit;
+ int64_t limit;
try {
- limit = std::stoi(args[0]);
+ limit = std::stoll(args[0]);
}
- catch(std::invalid_argument& ex) {
+ catch(const std::invalid_argument& ex) {
+ std::cout << "failed to parse argument" << std::endl;
return false;
}
- if (limit==-1) limit=128;
- limit *= 1024;
+ if (limit > 0)
+ limit *= 1024;
- return m_executor.set_limit(limit);
+ return m_executor.set_limit(limit, limit);
}
bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& args)
@@ -353,17 +359,18 @@ bool t_command_parser_executor::set_limit_up(const std::vector<std::string>& arg
if(args.size()==0) {
return m_executor.get_limit_up();
}
- int limit;
+ int64_t limit;
try {
- limit = std::stoi(args[0]);
+ limit = std::stoll(args[0]);
}
- catch(std::invalid_argument& ex) {
+ catch(const std::invalid_argument& ex) {
+ std::cout << "failed to parse argument" << std::endl;
return false;
}
- if (limit==-1) limit=128;
- limit *= 1024;
+ if (limit > 0)
+ limit *= 1024;
- return m_executor.set_limit_up(limit);
+ return m_executor.set_limit(0, limit);
}
bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& args)
@@ -372,17 +379,18 @@ bool t_command_parser_executor::set_limit_down(const std::vector<std::string>& a
if(args.size()==0) {
return m_executor.get_limit_down();
}
- int limit;
+ int64_t limit;
try {
- limit = std::stoi(args[0]);
+ limit = std::stoll(args[0]);
}
- catch(std::invalid_argument& ex) {
+ catch(const std::invalid_argument& ex) {
+ std::cout << "failed to parse argument" << std::endl;
return false;
}
- if (limit==-1) limit=128;
- limit *= 1024;
+ if (limit > 0)
+ limit *= 1024;
- return m_executor.set_limit_down(limit);
+ return m_executor.set_limit(limit, 0);
}
bool t_command_parser_executor::out_peers(const std::vector<std::string>& args)
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index f301ef14a..6443d9be0 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -36,7 +36,7 @@
#pragma once
-#include <boost/optional/optional_fwd.hpp>
+#include <boost/optional/optional.hpp>
#include "daemon/rpc_command_executor.h"
#include "common/common_fwd.h"
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index b9f503c6b..3f1543857 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -141,7 +141,7 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"set_log"
, std::bind(&t_command_parser_executor::set_log_level, &m_parser, p::_1)
- , "set_log <level>|<categories> - Change current loglevel, <level> is a number 0-4"
+ , "set_log <level>|<{+,-,}categories> - Change current log level/categories, <level> is a number 0-4"
);
m_command_lookup.set_handler(
"diff"
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index 8f6d542b6..acc23b9f9 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -88,6 +88,7 @@ int main(int argc, char const * argv[])
bf::path default_log = default_data_dir / std::string(CRYPTONOTE_NAME ".log");
command_line::add_arg(core_settings, daemon_args::arg_log_file, default_log.string());
command_line::add_arg(core_settings, daemon_args::arg_log_level);
+ command_line::add_arg(core_settings, daemon_args::arg_max_log_file_size);
command_line::add_arg(core_settings, daemon_args::arg_max_concurrency);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_ip);
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_port);
@@ -207,7 +208,7 @@ int main(int argc, char const * argv[])
if (! vm["log-file"].defaulted())
log_file_path = command_line::get_arg(vm, daemon_args::arg_log_file);
log_file_path = bf::absolute(log_file_path, relative_path_base);
- mlog_configure(log_file_path.string(), true);
+ mlog_configure(log_file_path.string(), true, command_line::get_arg(vm, daemon_args::arg_max_log_file_size));
// Set log level
if (!vm["log-level"].defaulted())
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 167e24ed3..ef593237c 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -599,7 +599,7 @@ bool t_rpc_command_executor::set_log_categories(const std::string &categories) {
}
}
- tools::success_msg_writer() << "Log categories are now " << categories;
+ tools::success_msg_writer() << "Log categories are now " << res.categories;
return true;
}
@@ -700,6 +700,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) {
std::string fail_message = "Problem fetching transaction";
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(transaction_hash));
+ req.decode_as_json = false;
if (m_is_rpc)
{
if (!m_rpc_client->rpc_request(req, res, "/gettransactions", fail_message.c_str()))
@@ -1129,48 +1130,115 @@ bool t_rpc_command_executor::print_status()
bool t_rpc_command_executor::get_limit()
{
- int limit_down = epee::net_utils::connection_basic::get_rate_down_limit( );
- int limit_up = epee::net_utils::connection_basic::get_rate_up_limit( );
- std::cout << "limit-down is " << limit_down/1024 << " kB/s" << std::endl;
- std::cout << "limit-up is " << limit_up/1024 << " kB/s" << std::endl;
- return true;
+ cryptonote::COMMAND_RPC_GET_LIMIT::request req;
+ cryptonote::COMMAND_RPC_GET_LIMIT::response res;
+
+ std::string failure_message = "Couldn't get limit";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/get_limit", failure_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_limit(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(failure_message, res.status);
+ return true;
+ }
+ }
+
+ tools::msg_writer() << "limit-down is " << res.limit_down/1024 << " kB/s";
+ tools::msg_writer() << "limit-up is " << res.limit_up/1024 << " kB/s";
+ return true;
}
-bool t_rpc_command_executor::set_limit(int limit)
+bool t_rpc_command_executor::set_limit(int64_t limit_down, int64_t limit_up)
{
- epee::net_utils::connection_basic::set_rate_down_limit( limit );
- epee::net_utils::connection_basic::set_rate_up_limit( limit );
- std::cout << "Set limit-down to " << limit/1024 << " kB/s" << std::endl;
- std::cout << "Set limit-up to " << limit/1024 << " kB/s" << std::endl;
- return true;
+ cryptonote::COMMAND_RPC_SET_LIMIT::request req;
+ cryptonote::COMMAND_RPC_SET_LIMIT::response res;
+
+ req.limit_down = limit_down;
+ req.limit_up = limit_up;
+
+ std::string failure_message = "Couldn't set limit";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/set_limit", failure_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_set_limit(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(failure_message, res.status);
+ return true;
+ }
+ }
+
+ tools::msg_writer() << "Set limit-down to " << res.limit_down/1024 << " kB/s";
+ tools::msg_writer() << "Set limit-up to " << res.limit_up/1024 << " kB/s";
+ return true;
}
bool t_rpc_command_executor::get_limit_up()
{
- int limit_up = epee::net_utils::connection_basic::get_rate_up_limit( );
- std::cout << "limit-up is " << limit_up/1024 << " kB/s" << std::endl;
- return true;
-}
+ cryptonote::COMMAND_RPC_GET_LIMIT::request req;
+ cryptonote::COMMAND_RPC_GET_LIMIT::response res;
-bool t_rpc_command_executor::set_limit_up(int limit)
-{
- epee::net_utils::connection_basic::set_rate_up_limit( limit );
- std::cout << "Set limit-up to " << limit/1024 << " kB/s" << std::endl;
- return true;
+ std::string failure_message = "Couldn't get limit";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/get_limit", failure_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_limit(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(failure_message, res.status);
+ return true;
+ }
+ }
+
+ tools::msg_writer() << "limit-up is " << res.limit_up/1024 << " kB/s";
+ return true;
}
bool t_rpc_command_executor::get_limit_down()
{
- int limit_down = epee::net_utils::connection_basic::get_rate_down_limit( );
- std::cout << "limit-down is " << limit_down/1024 << " kB/s" << std::endl;
- return true;
-}
+ cryptonote::COMMAND_RPC_GET_LIMIT::request req;
+ cryptonote::COMMAND_RPC_GET_LIMIT::response res;
-bool t_rpc_command_executor::set_limit_down(int limit)
-{
- epee::net_utils::connection_basic::set_rate_down_limit( limit );
- std::cout << "Set limit-down to " << limit/1024 << " kB/s" << std::endl;
- return true;
+ std::string failure_message = "Couldn't get limit";
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/get_limit", failure_message.c_str()))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_get_limit(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(failure_message, res.status);
+ return true;
+ }
+ }
+
+ tools::msg_writer() << "limit-down is " << res.limit_down/1024 << " kB/s";
+ return true;
}
bool t_rpc_command_executor::out_peers(uint64_t limit)
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index fc0b39654..d79707a6f 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -119,11 +119,7 @@ public:
bool get_limit_down();
- bool set_limit(int limit);
-
- bool set_limit_up(int limit);
-
- bool set_limit_down(int limit);
+ bool set_limit(int64_t limit_down, int64_t limit_up);
bool out_peers(uint64_t limit);
diff --git a/src/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt
index 99198dc57..7a82c12d9 100644
--- a/src/debug_utilities/CMakeLists.txt
+++ b/src/debug_utilities/CMakeLists.txt
@@ -42,8 +42,6 @@ target_link_libraries(cn_deserialize
epee
${CMAKE_THREAD_LIBS_INIT})
-add_dependencies(cn_deserialize
- version)
set_property(TARGET cn_deserialize
PROPERTY
OUTPUT_NAME "monero-utils-deserialize")
@@ -65,8 +63,6 @@ target_link_libraries(object_sizes
epee
${CMAKE_THREAD_LIBS_INIT})
-add_dependencies(object_sizes
- version)
set_property(TARGET object_sizes
PROPERTY
OUTPUT_NAME "monero-utils-object-sizes")
diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt
index 0704940b5..123b0a272 100644
--- a/src/p2p/CMakeLists.txt
+++ b/src/p2p/CMakeLists.txt
@@ -39,6 +39,7 @@ monero_add_library(p2p ${P2P})
target_link_libraries(p2p
PUBLIC
epee
+ version
${UPNP_LIBRARIES}
${Boost_CHRONO_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
@@ -47,5 +48,3 @@ target_link_libraries(p2p
${Boost_THREAD_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
-add_dependencies(p2p
- version)
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 7da123633..f1ca50f76 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -1916,6 +1916,8 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::gray_peerlist_housekeeping()
{
+ if (!m_exclusive_peers.empty()) return true;
+
peerlist_entry pe = AUTO_VAL_INIT(pe);
if (m_net_server.is_stop_signal_sent())
diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h
index a30a05422..8372445aa 100644
--- a/src/p2p/net_peerlist.h
+++ b/src/p2p/net_peerlist.h
@@ -190,35 +190,16 @@ namespace nodetool
if (ver < 6)
return;
- if(ver < 3)
- return;
CRITICAL_REGION_LOCAL(m_peerlist_lock);
- if(ver < 4)
- {
- //loading data from old storage
- peers_indexed_old pio;
- a & pio;
- peers_indexed_from_old(pio, m_peers_white);
- return;
- }
#if 0
// trouble loading more than one peer, can't find why
a & m_peers_white;
a & m_peers_gray;
+ a & m_peers_anchor;
#else
serialize_peers(a, m_peers_white, peerlist_entry(), ver);
serialize_peers(a, m_peers_gray, peerlist_entry(), ver);
-#endif
-
- if(ver < 5) {
- return;
- }
-
-#if 0
- // trouble loading more than one peer, can't find why
- a & m_peers_anchor;
-#else
serialize_peers(a, m_peers_anchor, anchor_peerlist_entry(), ver);
#endif
}
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index b5c38b1a8..23bb6aaae 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -117,10 +117,3 @@ target_link_libraries(daemon_rpc_server
${EXTRA_LIBRARIES})
target_include_directories(daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH})
target_include_directories(obj_daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH})
-
-
-add_dependencies(rpc
- version)
-
-add_dependencies(daemon_rpc_server
- version)
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 1f7f4a1ff..9b91f438a 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -50,6 +50,16 @@ using namespace epee;
#define MAX_RESTRICTED_FAKE_OUTS_COUNT 40
#define MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT 500
+namespace
+{
+ void add_reason(std::string &reasons, const char *reason)
+ {
+ if (!reasons.empty())
+ reasons += ", ";
+ reasons += reason;
+ }
+}
+
namespace cryptonote
{
@@ -128,11 +138,7 @@ namespace cryptonote
{
CHECK_CORE_BUSY();
crypto::hash top_hash;
- if (!m_core.get_blockchain_top(res.height, top_hash))
- {
- res.status = "Failed";
- return false;
- }
+ m_core.get_blockchain_top(res.height, top_hash);
++res.height; // turn top block height into blockchain height
res.top_block_hash = string_tools::pod_to_hex(top_hash);
res.target_height = m_core.get_target_blockchain_height();
@@ -478,18 +484,30 @@ namespace cryptonote
bool r = m_core.get_pool_transactions(pool_txs);
if(r)
{
- for (std::list<transaction>::const_iterator i = pool_txs.begin(); i != pool_txs.end(); ++i)
+ // sort to match original request
+ std::list<transaction> sorted_txs;
+ std::list<cryptonote::transaction>::const_iterator i;
+ for (const crypto::hash &h: vh)
{
- crypto::hash tx_hash = get_transaction_hash(*i);
- std::list<crypto::hash>::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), tx_hash);
- if (mi != missed_txs.end())
+ if (std::find(missed_txs.begin(), missed_txs.end(), h) == missed_txs.end())
{
- pool_tx_hashes.insert(tx_hash);
- missed_txs.erase(mi);
- txs.push_back(*i);
+ // core returns the ones it finds in the right order
+ if (get_transaction_hash(txs.front()) != h)
+ {
+ res.status = "Failed: tx hash mismatch";
+ return true;
+ }
+ sorted_txs.push_back(std::move(txs.front()));
+ txs.pop_front();
+ }
+ else if ((i = std::find_if(pool_txs.begin(), pool_txs.end(), [h](cryptonote::transaction &tx) { return h == cryptonote::get_transaction_hash(tx); })) != pool_txs.end())
+ {
+ sorted_txs.push_back(*i);
+ missed_txs.remove(h);
++found_in_pool;
}
}
+ txs = sorted_txs;
}
LOG_PRINT_L2("Found " << found_in_pool << "/" << vh.size() << " transactions in the pool");
}
@@ -510,11 +528,12 @@ namespace cryptonote
e.in_pool = pool_tx_hashes.find(tx_hash) != pool_tx_hashes.end();
if (e.in_pool)
{
- e.block_height = std::numeric_limits<uint64_t>::max();
+ e.block_height = e.block_timestamp = std::numeric_limits<uint64_t>::max();
}
else
{
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);
}
// fill up old style responses too, in case an old wallet asks
@@ -623,31 +642,33 @@ namespace cryptonote
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)
{
- if (tvc.m_verifivation_failed)
- {
- LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed");
- }
- else
- {
- LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx");
- }
res.status = "Failed";
+ res.reason = "";
if ((res.low_mixin = tvc.m_low_mixin))
- res.reason = "ring size too small";
+ add_reason(res.reason, "ring size too small");
if ((res.double_spend = tvc.m_double_spend))
- res.reason = "double spend";
+ add_reason(res.reason, "double spend");
if ((res.invalid_input = tvc.m_invalid_input))
- res.reason = "invalid input";
+ add_reason(res.reason, "invalid input");
if ((res.invalid_output = tvc.m_invalid_output))
- res.reason = "invalid output";
+ add_reason(res.reason, "invalid output");
if ((res.too_big = tvc.m_too_big))
- res.reason = "too big";
+ add_reason(res.reason, "too big");
if ((res.overspend = tvc.m_overspend))
- res.reason = "overspend";
+ add_reason(res.reason, "overspend");
if ((res.fee_too_low = tvc.m_fee_too_low))
- res.reason = "fee too low";
+ add_reason(res.reason, "fee too low");
if ((res.not_rct = tvc.m_not_rct))
- res.reason = "tx is not ringct";
+ add_reason(res.reason, "tx is not ringct");
+ const std::string punctuation = res.reason.empty() ? "" : ": ";
+ if (tvc.m_verifivation_failed)
+ {
+ LOG_PRINT_L0("[on_send_raw_tx]: tx verification failed" << punctuation << res.reason);
+ }
+ else
+ {
+ LOG_PRINT_L0("[on_send_raw_tx]: Failed to process tx" << punctuation << res.reason);
+ }
return true;
}
@@ -810,6 +831,7 @@ namespace cryptonote
bool core_rpc_server::on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res)
{
mlog_set_log(req.categories.c_str());
+ res.categories = mlog_get_categories();
res.status = CORE_RPC_STATUS_OK;
return true;
}
@@ -948,7 +970,7 @@ namespace cryptonote
LOG_ERROR("Failed to find tx pub key in blockblob");
return false;
}
- res.reserved_offset += sizeof(tx_pub_key) + 3; //3 bytes: tag for TX_EXTRA_TAG_PUBKEY(1 byte), tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
+ 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(res.reserved_offset + req.reserve_size > block_blob.size())
{
error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
@@ -1048,13 +1070,7 @@ namespace cryptonote
}
uint64_t last_block_height;
crypto::hash last_block_hash;
- bool have_last_block_hash = m_core.get_blockchain_top(last_block_height, last_block_hash);
- if (!have_last_block_hash)
- {
- error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR;
- error_resp.message = "Internal error: can't get last block hash.";
- return false;
- }
+ m_core.get_blockchain_top(last_block_height, last_block_hash);
block last_block;
bool have_last_block = m_core.get_block_by_hash(last_block_hash, last_block);
if (!have_last_block)
@@ -1287,11 +1303,7 @@ namespace cryptonote
}
crypto::hash top_hash;
- if (!m_core.get_blockchain_top(res.height, top_hash))
- {
- res.status = "Failed";
- return false;
- }
+ m_core.get_blockchain_top(res.height, top_hash);
++res.height; // turn top block height into blockchain height
res.top_block_hash = string_tools::pod_to_hex(top_hash);
res.target_height = m_core.get_target_blockchain_height();
@@ -1522,6 +1534,53 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res)
+ {
+ res.limit_down = epee::net_utils::connection_basic::get_rate_down_limit();
+ res.limit_up = epee::net_utils::connection_basic::get_rate_up_limit();
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool core_rpc_server::on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res)
+ {
+ // -1 = reset to default
+ // 0 = do not modify
+
+ if (req.limit_down > 0)
+ {
+ epee::net_utils::connection_basic::set_rate_down_limit(req.limit_down);
+ }
+ else if (req.limit_down < 0)
+ {
+ if (req.limit_down != -1)
+ {
+ res.status = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ return false;
+ }
+ epee::net_utils::connection_basic::set_rate_down_limit(nodetool::default_limit_down * 1024);
+ }
+
+ if (req.limit_up > 0)
+ {
+ epee::net_utils::connection_basic::set_rate_up_limit(req.limit_up);
+ }
+ else if (req.limit_up < 0)
+ {
+ if (req.limit_up != -1)
+ {
+ res.status = CORE_RPC_ERROR_CODE_WRONG_PARAM;
+ return false;
+ }
+ epee::net_utils::connection_basic::set_rate_up_limit(nodetool::default_limit_up * 1024);
+ }
+
+ res.limit_down = epee::net_utils::connection_basic::get_rate_down_limit();
+ res.limit_up = epee::net_utils::connection_basic::get_rate_up_limit();
+ res.status = CORE_RPC_STATUS_OK;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res)
{
// TODO
@@ -1560,8 +1619,10 @@ namespace cryptonote
static const char software[] = "monero";
#ifdef BUILD_TAG
static const char buildtag[] = BOOST_PP_STRINGIZE(BUILD_TAG);
+ static const char subdir[] = "cli";
#else
static const char buildtag[] = "source";
+ static const char subdir[] = "source";
#endif
if (req.command != "check" && req.command != "download" && req.command != "update")
@@ -1584,8 +1645,8 @@ namespace cryptonote
}
res.update = true;
res.version = version;
- res.user_uri = tools::get_update_url(software, "cli", buildtag, version, true);
- res.auto_uri = tools::get_update_url(software, "cli", buildtag, version, false);
+ res.user_uri = tools::get_update_url(software, subdir, buildtag, version, true);
+ res.auto_uri = tools::get_update_url(software, subdir, buildtag, version, false);
res.hash = hash;
if (req.command == "check")
{
@@ -1703,11 +1764,7 @@ namespace cryptonote
}
crypto::hash top_hash;
- if (!m_core.get_blockchain_top(res.height, top_hash))
- {
- res.status = "Failed";
- return false;
- }
+ m_core.get_blockchain_top(res.height, top_hash);
++res.height; // turn top block height into blockchain height
res.target_height = m_core.get_target_blockchain_height();
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index dbbe07972..73a308a72 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -97,6 +97,8 @@ namespace cryptonote
MAP_URI_AUTO_JON2("/get_transaction_pool_stats", on_get_transaction_pool_stats, COMMAND_RPC_GET_TRANSACTION_POOL_STATS)
MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted)
MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO)
+ MAP_URI_AUTO_JON2("/get_limit", on_get_limit, COMMAND_RPC_GET_LIMIT)
+ MAP_URI_AUTO_JON2_IF("/set_limit", on_set_limit, COMMAND_RPC_SET_LIMIT, !m_restricted)
MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted)
MAP_URI_AUTO_JON2_IF("/start_save_graph", on_start_save_graph, COMMAND_RPC_START_SAVE_GRAPH, !m_restricted)
MAP_URI_AUTO_JON2_IF("/stop_save_graph", on_stop_save_graph, COMMAND_RPC_STOP_SAVE_GRAPH, !m_restricted)
@@ -155,6 +157,8 @@ namespace cryptonote
bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res);
bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res);
bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res);
+ bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res);
+ bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res);
bool on_out_peers(const COMMAND_RPC_OUT_PEERS::request& req, COMMAND_RPC_OUT_PEERS::response& res);
bool on_start_save_graph(const COMMAND_RPC_START_SAVE_GRAPH::request& req, COMMAND_RPC_START_SAVE_GRAPH::response& res);
bool on_stop_save_graph(const COMMAND_RPC_STOP_SAVE_GRAPH::request& req, COMMAND_RPC_STOP_SAVE_GRAPH::response& res);
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 88327dd75..85ac2ca30 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -49,7 +49,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 1
-#define CORE_RPC_VERSION_MINOR 13
+#define CORE_RPC_VERSION_MINOR 14
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -215,6 +215,7 @@ namespace cryptonote
std::string as_json;
bool in_pool;
uint64_t block_height;
+ uint64_t block_timestamp;
std::vector<uint64_t> output_indices;
BEGIN_KV_SERIALIZE_MAP()
@@ -223,6 +224,7 @@ namespace cryptonote
KV_SERIALIZE(as_json)
KV_SERIALIZE(in_pool)
KV_SERIALIZE(block_height)
+ KV_SERIALIZE(block_timestamp)
KV_SERIALIZE(output_indices)
END_KV_SERIALIZE_MAP()
};
@@ -979,8 +981,11 @@ namespace cryptonote
struct response
{
std::string status;
+ std::string categories;
+
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
+ KV_SERIALIZE(categories)
END_KV_SERIALIZE_MAP()
};
};
@@ -1242,6 +1247,55 @@ namespace cryptonote
};
};
+ struct COMMAND_RPC_GET_LIMIT
+ {
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+ uint64_t limit_up;
+ uint64_t limit_down;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(limit_up)
+ KV_SERIALIZE(limit_down)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_SET_LIMIT
+ {
+ struct request
+ {
+ int64_t limit_down;
+ int64_t limit_up;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(limit_down)
+ KV_SERIALIZE(limit_up)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string status;
+ uint64_t limit_up;
+ uint64_t limit_down;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(status)
+ KV_SERIALIZE(limit_up)
+ KV_SERIALIZE(limit_down)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
struct COMMAND_RPC_OUT_PEERS
{
struct request
diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp
index 53eeb5e76..9a6c61b10 100644
--- a/src/rpc/daemon_handler.cpp
+++ b/src/rpc/daemon_handler.cpp
@@ -542,7 +542,7 @@ namespace rpc
{
if (m_core.get_current_blockchain_height() <= req.height)
{
- res.hash = cryptonote::null_hash;
+ res.hash = crypto::null_hash;
res.status = Message::STATUS_FAILED;
res.error_details = "height given is higher than current chain height";
return;
diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp
index e35389f9c..a40821d19 100644
--- a/src/serialization/json_object.cpp
+++ b/src/serialization/json_object.cpp
@@ -776,6 +776,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx)
GET_FROM_JSON_OBJECT(val, tx.receive_time, receive_time);
GET_FROM_JSON_OBJECT(val, tx.last_relayed_time, last_relayed_time);
GET_FROM_JSON_OBJECT(val, tx.relayed, relayed);
+ GET_FROM_JSON_OBJECT(val, tx.do_not_relay, do_not_relay);
}
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::hard_fork_info& info, rapidjson::Value& val)
diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h
index 639240820..869f5d10e 100644
--- a/src/serialization/serialization.h
+++ b/src/serialization/serialization.h
@@ -41,6 +41,7 @@
#pragma once
#include <vector>
+#include <deque>
#include <list>
#include <string>
#include <boost/type_traits/is_integral.hpp>
@@ -198,6 +199,11 @@ inline bool do_serialize(Archive &ar, bool &v)
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \
::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving())
+/*! \macro PREPARE_CUSTOM_DEQUE_SERIALIZATION
+ */
+#define PREPARE_CUSTOM_DEQUE_SERIALIZATION(size, vec) \
+ ::serialization::detail::prepare_custom_deque_serialization(size, vec, typename Archive<W>::is_saving())
+
/*! \macro END_SERIALIZE
* \brief self-explanatory
*/
@@ -292,6 +298,17 @@ namespace serialization {
vec.resize(size);
}
+ template <typename T>
+ void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<true>& /*is_saving*/)
+ {
+ }
+
+ template <typename T>
+ void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<false>& /*is_saving*/)
+ {
+ vec.resize(size);
+ }
+
/*! \fn do_check_stream_state
*
* \brief self explanatory
diff --git a/src/serialization/vector.h b/src/serialization/vector.h
index 598cfb92e..12fd59558 100644
--- a/src/serialization/vector.h
+++ b/src/serialization/vector.h
@@ -37,6 +37,11 @@ bool do_serialize(Archive<false> &ar, std::vector<T> &v);
template <template <bool> class Archive, class T>
bool do_serialize(Archive<true> &ar, std::vector<T> &v);
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::deque<T> &v);
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::deque<T> &v);
+
namespace serialization
{
namespace detail
@@ -64,7 +69,7 @@ namespace serialization
}
template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::vector<T> &v)
+bool do_serialize_vd(Archive<false> &ar, T &v)
{
size_t cnt;
ar.begin_array(cnt);
@@ -93,7 +98,7 @@ bool do_serialize(Archive<false> &ar, std::vector<T> &v)
}
template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::vector<T> &v)
+bool do_serialize_vd(Archive<true> &ar, T &v)
{
size_t cnt = v.size();
ar.begin_array(cnt);
@@ -110,3 +115,13 @@ bool do_serialize(Archive<true> &ar, std::vector<T> &v)
ar.end_array();
return true;
}
+
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::vector<T> &v) { return do_serialize_vd(ar, v); }
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::vector<T> &v) { return do_serialize_vd(ar, v); }
+
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::deque<T> &v) { return do_serialize_vd(ar, v); }
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::deque<T> &v) { return do_serialize_vd(ar, v); }
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt
index 443e9b87e..b56085b8f 100644
--- a/src/simplewallet/CMakeLists.txt
+++ b/src/simplewallet/CMakeLists.txt
@@ -49,14 +49,13 @@ target_link_libraries(simplewallet
common
mnemonics
p2p
+ version
${Boost_CHRONO_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
-add_dependencies(simplewallet
- version)
set_property(TARGET simplewallet
PROPERTY
OUTPUT_NAME "monero-wallet-cli")
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 86d0b1916..b7d6a82bf 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -290,7 +290,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
return true;
}
-bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+bool simple_wallet::print_seed(bool encrypted)
{
bool success = false;
std::string electrum_words;
@@ -311,7 +311,16 @@ bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<st
m_wallet->set_seed_language(mnemonic_language);
}
- success = m_wallet->get_seed(electrum_words);
+ std::string seed_pass;
+ if (encrypted)
+ {
+ auto pwd_container = tools::password_container::prompt(true, tr("Enter optional seed encryption passphrase, empty to see raw seed"));
+ if (std::cin.eof() || !pwd_container)
+ return true;
+ seed_pass = pwd_container->password();
+ }
+
+ success = m_wallet->get_seed(electrum_words, seed_pass);
}
if (success)
@@ -325,6 +334,16 @@ bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<st
return true;
}
+bool simple_wallet::seed(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ return print_seed(false);
+}
+
+bool simple_wallet::encrypted_seed(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ return print_seed(true);
+}
+
bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if (m_wallet->watch_only())
@@ -747,7 +766,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("donate", boost::bind(&simple_wallet::donate, this, _1), tr("donate [<ring_size>] <amount> [payment_id] - Donate <amount> to the development team (donate.getmonero.org)"));
m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), tr("Sign a transaction from a file"));
m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), tr("Submit a signed transaction from a file"));
- m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log <level>|<categories> - Change current log detail (level must be <0-4>)"));
+ m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log <level>|{+,-,}<categories> - Change current log detail (level must be <0-4>)"));
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), tr("Show current wallet public address"));
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::print_integrated_address, this, _1), tr("integrated_address [PID] - Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID"));
m_cmd_binder.set_handler("address_book", boost::bind(&simple_wallet::address_book, this, _1), tr("address_book [(add (<address> [pid <long or short payment id>])|<integrated address> [<description possibly with whitespaces>])|(delete <index>)] - Print all entries in the address book, optionally adding/deleting an entry to/from it"));
@@ -757,6 +776,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), tr("Display private spend key"));
m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Display Electrum-style mnemonic seed"));
m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; print-ring-members <1|0> - whether to print detailed information about ring members during confirmation; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-ring-size <n> - set default ring size (default is 5); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id <1|0>; ask-password <1|0>; unit <monero|millinero|micronero|nanonero|piconero> - set default monero (sub-)unit; min-outputs-count [n] - try to keep at least that many outputs of value at least min-outputs-value; min-outputs-value [n] - try to keep at least min-outputs-count outputs of at least that value; merge-destinations <1|0> - whether to merge multiple payments to the same destination address; confirm-backlog <1|0> - whether to warn if there is transaction backlog"));
+ m_cmd_binder.set_handler("encrypted_seed", boost::bind(&simple_wallet::encrypted_seed, this, _1), tr("Display encrypted Electrum-style mnemonic seed"));
m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs"));
m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), tr("Get transaction key (r) for a given <txid>"));
m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to <address> in <txid>"));
@@ -855,12 +875,14 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::set_log(const std::vector<std::string> &args)
{
- if(args.size() != 1)
+ if(args.size() > 1)
{
fail_msg_writer() << tr("usage: set_log <log_level_number_0-4> | <categories>");
return true;
}
- mlog_set_log(args[0].c_str());
+ if (!args.empty())
+ mlog_set_log(args[0].c_str());
+ success_msg_writer() << "New log categories: " << mlog_get_categories();
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -1027,6 +1049,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("Electrum-style word list failed verification");
return false;
}
+
+ auto pwd_container = tools::password_container::prompt(false, tr("Enter seed encryption passphrase, empty if none"));
+ if (std::cin.eof() || !pwd_container)
+ return false;
+ std::string seed_pass = pwd_container->password();
+ if (!seed_pass.empty())
+ m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
}
if (!m_generate_from_view_key.empty())
{
@@ -1684,9 +1713,18 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to load wallet: ") << e.what();
- // only suggest removing cache if the password was actually correct
- if (m_wallet && m_wallet->verify_password(password))
- fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % m_wallet_file;
+ if (m_wallet)
+ {
+ // only suggest removing cache if the password was actually correct
+ bool password_is_correct = false;
+ try
+ {
+ password_is_correct = m_wallet->verify_password(password);
+ }
+ catch (...) { } // guard against I/O errors
+ if (password_is_correct)
+ fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % m_wallet_file;
+ }
return false;
}
success_msg_writer() <<
@@ -3245,7 +3283,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
std::vector<tx_extra_field> tx_extra_fields;
bool has_encrypted_payment_id = false;
- crypto::hash8 payment_id8 = cryptonote::null_hash8;
+ crypto::hash8 payment_id8 = crypto::null_hash8;
if (cryptonote::parse_tx_extra(cd.extra, tx_extra_fields))
{
tx_extra_nonce extra_nonce;
@@ -3478,6 +3516,9 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
catch (const tools::error::tx_rejected& e)
{
fail_msg_writer() << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
+ std::string reason = e.reason();
+ if (!reason.empty())
+ fail_msg_writer() << tr("Reason: ") << reason;
}
catch (const tools::error::tx_sum_overflow& e)
{
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 30c428810..3b29e3ca2 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -97,6 +97,7 @@ namespace cryptonote
bool viewkey(const std::vector<std::string> &args = std::vector<std::string>());
bool spendkey(const std::vector<std::string> &args = std::vector<std::string>());
bool seed(const std::vector<std::string> &args = std::vector<std::string>());
+ bool encrypted_seed(const std::vector<std::string> &args = std::vector<std::string>());
/*!
* \brief Sets seed language.
@@ -186,6 +187,7 @@ namespace cryptonote
bool accept_loaded_tx(const tools::wallet2::signed_tx_set &txs);
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
std::string get_prompt() const;
+ bool print_seed(bool encrypted);
/*!
* \brief Prints the seed with a nice message
diff --git a/src/version.cmake b/src/version.cmake
index 623d3cf1f..45a97cd20 100644
--- a/src/version.cmake
+++ b/src/version.cmake
@@ -36,7 +36,7 @@ if(RET)
message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.")
set(VERSIONTAG "unknown")
- configure_file("src/version.h.in" "${TO}")
+ configure_file("src/version.cpp.in" "${TO}")
else()
message(STATUS "You are currently on commit ${COMMIT}")
@@ -59,5 +59,5 @@ else()
endif()
endif()
- configure_file("src/version.h.in" "${TO}")
+ configure_file("src/version.cpp.in" "${TO}")
endif()
diff --git a/src/version.cpp.in b/src/version.cpp.in
new file mode 100644
index 000000000..d1444f867
--- /dev/null
+++ b/src/version.cpp.in
@@ -0,0 +1,11 @@
+#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
+#define DEF_MONERO_VERSION "0.11.0.0"
+#define DEF_MONERO_RELEASE_NAME "Helium Hydra"
+#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
+
+#include "version.h"
+
+const char* const MONERO_VERSION_TAG = DEF_MONERO_VERSION_TAG;
+const char* const MONERO_VERSION = DEF_MONERO_VERSION;
+const char* const MONERO_RELEASE_NAME = DEF_MONERO_RELEASE_NAME;
+const char* const MONERO_VERSION_FULL = DEF_MONERO_VERSION_FULL;
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 000000000..d1d06c790
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,6 @@
+#pragma once
+
+extern const char* const MONERO_VERSION_TAG;
+extern const char* const MONERO_VERSION;
+extern const char* const MONERO_RELEASE_NAME;
+extern const char* const MONERO_VERSION_FULL;
diff --git a/src/version.h.in b/src/version.h.in
deleted file mode 100644
index 281b52db4..000000000
--- a/src/version.h.in
+++ /dev/null
@@ -1,4 +0,0 @@
-#define MONERO_VERSION_TAG "@VERSIONTAG@"
-#define MONERO_VERSION "0.11.0.0"
-#define MONERO_RELEASE_NAME "Helium Hydra"
-#define MONERO_VERSION_FULL MONERO_VERSION "-" MONERO_VERSION_TAG
diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt
index 639080051..fe87d0de1 100644
--- a/src/wallet/CMakeLists.txt
+++ b/src/wallet/CMakeLists.txt
@@ -84,7 +84,6 @@ target_link_libraries(wallet
${Boost_REGEX_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
-add_dependencies(wallet version)
if (NOT BUILD_GUI_DEPS)
set(wallet_rpc_sources
@@ -110,13 +109,13 @@ if (NOT BUILD_GUI_DEPS)
cryptonote_core
cncrypto
common
+ version
${Boost_CHRONO_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
- add_dependencies(wallet_rpc_server version)
set_property(TARGET wallet_rpc_server
PROPERTY
OUTPUT_NAME "monero-wallet-rpc")
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp
index 28f835ebd..9605047b7 100644
--- a/src/wallet/api/address_book.cpp
+++ b/src/wallet/api/address_book.cpp
@@ -42,7 +42,7 @@ namespace Monero {
AddressBook::~AddressBook() {}
AddressBookImpl::AddressBookImpl(WalletImpl *wallet)
- : m_wallet(wallet) {}
+ : m_wallet(wallet), m_errorCode(Status_Ok) {}
bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &payment_id_str, const std::string &description)
{
@@ -57,7 +57,7 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
return false;
}
- crypto::hash payment_id = cryptonote::null_hash;
+ crypto::hash payment_id = crypto::null_hash;
bool has_long_pid = (payment_id_str.empty())? false : tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
// Short payment id provided
@@ -106,7 +106,7 @@ void AddressBookImpl::refresh()
for (size_t i = 0; i < rows.size(); ++i) {
tools::wallet2::address_book_row * row = &rows.at(i);
- std::string payment_id = (row->m_payment_id == cryptonote::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id);
+ std::string payment_id = (row->m_payment_id == crypto::null_hash)? "" : epee::string_tools::pod_to_hex(row->m_payment_id);
std::string address = cryptonote::get_account_address_as_str(m_wallet->m_wallet->testnet(),row->m_address);
// convert the zero padded short payment id to integrated address
if (payment_id.length() > 16 && payment_id.substr(16).find_first_not_of('0') == std::string::npos) {
diff --git a/src/wallet/api/unsigned_transaction.cpp b/src/wallet/api/unsigned_transaction.cpp
index 961bd772a..5105278e4 100644
--- a/src/wallet/api/unsigned_transaction.cpp
+++ b/src/wallet/api/unsigned_transaction.cpp
@@ -230,13 +230,13 @@ std::vector<std::string> UnsignedTransactionImpl::paymentId() const
{
std::vector<string> result;
for (const auto &utx: m_unsigned_tx_set.txes) {
- crypto::hash payment_id = cryptonote::null_hash;
+ crypto::hash payment_id = crypto::null_hash;
cryptonote::tx_extra_nonce extra_nonce;
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
cryptonote::parse_tx_extra(utx.extra, tx_extra_fields);
if (cryptonote::find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
{
- crypto::hash8 payment_id8 = cryptonote::null_hash8;
+ crypto::hash8 payment_id8 = crypto::null_hash8;
if(cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
{
// We can't decrypt short pid without recipient key.
@@ -244,10 +244,10 @@ std::vector<std::string> UnsignedTransactionImpl::paymentId() const
}
else if (!cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
{
- payment_id = cryptonote::null_hash;
+ payment_id = crypto::null_hash;
}
}
- if(payment_id != cryptonote::null_hash)
+ if(payment_id != crypto::null_hash)
result.push_back(epee::string_tools::pod_to_hex(payment_id));
else
result.push_back("");
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index 7afc1f449..9cd72b543 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -303,7 +303,7 @@ WalletImpl::~WalletImpl()
// Pause refresh thread - prevents refresh from starting again
pauseRefresh();
// Close wallet - stores cache and stops ongoing refresh operation
- close();
+ close(false); // do not store wallet as part of the closing activities
// Stop refresh thread
stopRefresh();
delete m_wallet2Callback;
@@ -566,19 +566,21 @@ bool WalletImpl::recover(const std::string &path, const std::string &seed)
return m_status == Status_Ok;
}
-bool WalletImpl::close()
+bool WalletImpl::close(bool store)
{
bool result = false;
LOG_PRINT_L1("closing wallet...");
try {
- // Do not store wallet with invalid status
- // Status Critical refers to errors on opening or creating wallets.
- if (status() != Status_Critical)
- m_wallet->store();
- else
- LOG_ERROR("Status_Critical - not storing wallet");
- LOG_PRINT_L1("wallet::store done");
+ if (store) {
+ // Do not store wallet with invalid status
+ // Status Critical refers to errors on opening or creating wallets.
+ if (status() != Status_Critical)
+ m_wallet->store();
+ else
+ LOG_ERROR("Status_Critical - not storing wallet");
+ LOG_PRINT_L1("wallet::store done");
+ }
LOG_PRINT_L1("Calling wallet::stop...");
m_wallet->stop();
LOG_PRINT_L1("wallet::stop done");
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 8190c7873..1e3d1e600 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -63,7 +63,7 @@ public:
const std::string &address_string,
const std::string &viewkey_string,
const std::string &spendkey_string = "");
- bool close();
+ bool close(bool store = true);
std::string seed() const;
std::string getSeedLanguage() const;
void setSeedLanguage(const std::string &arg);
@@ -153,7 +153,6 @@ private:
std::string m_password;
TransactionHistoryImpl * m_history;
bool m_trustedDaemon;
- WalletListener * m_walletListener;
Wallet2CallbackImpl * m_wallet2Callback;
AddressBookImpl * m_addressBook;
diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp
index a23533530..897137d35 100644
--- a/src/wallet/api/wallet_manager.cpp
+++ b/src/wallet/api/wallet_manager.cpp
@@ -102,10 +102,12 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path,
return wallet;
}
-bool WalletManagerImpl::closeWallet(Wallet *wallet)
+bool WalletManagerImpl::closeWallet(Wallet *wallet, bool store)
{
WalletImpl * wallet_ = dynamic_cast<WalletImpl*>(wallet);
- bool result = wallet_->close();
+ if (!wallet_)
+ return false;
+ bool result = wallet_->close(store);
if (!result) {
m_errorString = wallet_->errorString();
} else {
diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h
index aa6ea439e..8455f0f16 100644
--- a/src/wallet/api/wallet_manager.h
+++ b/src/wallet/api/wallet_manager.h
@@ -48,7 +48,7 @@ public:
const std::string &addressString,
const std::string &viewKeyString,
const std::string &spendKeyString = "");
- virtual bool closeWallet(Wallet *wallet);
+ virtual bool closeWallet(Wallet *wallet, bool store = true);
bool walletExists(const std::string &path);
bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool watch_only) const;
std::vector<std::string> findWallets(const std::string &path);
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 805d5c737..08e1d2a09 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -33,6 +33,7 @@
#include <boost/format.hpp>
#include <boost/optional/optional.hpp>
#include <boost/utility/value_init.hpp>
+#include <boost/algorithm/string/join.hpp>
#include "include_base_utils.h"
using namespace epee;
@@ -289,6 +290,13 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file,
return false;
}
restore_deterministic_wallet = true;
+
+ GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed_passphrase, std::string, String, false, std::string());
+ if (field_seed_passphrase_found)
+ {
+ if (!field_seed_passphrase.empty())
+ recovery_key = cryptonote::decrypt_key(recovery_key, field_seed_passphrase);
+ }
}
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, address, std::string, String, false, std::string());
@@ -376,7 +384,11 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file,
cryptonote::account_public_address address2;
bool has_payment_id;
crypto::hash8 new_payment_id;
- get_account_integrated_address_from_str(address2, has_payment_id, new_payment_id, testnet, field_address);
+ if (!get_account_integrated_address_from_str(address2, has_payment_id, new_payment_id, testnet, field_address))
+ {
+ tools::fail_msg_writer() << tools::wallet2::tr("failed to parse address: ") << field_address;
+ return false;
+ }
address.m_spend_public_key = address2.m_spend_public_key;
}
wallet->generate(field_filename, field_password, address, viewkey);
@@ -419,6 +431,20 @@ static void throw_on_rpc_response_error(const boost::optional<std::string> &stat
THROW_WALLET_EXCEPTION_IF(*status != CORE_RPC_STATUS_OK, tools::error::wallet_generic_rpc_error, method, *status);
}
+std::string strjoin(const std::vector<size_t> &V, const char *sep)
+{
+ std::stringstream ss;
+ bool first = true;
+ for (const auto &v: V)
+ {
+ if (!first)
+ ss << sep;
+ ss << std::to_string(v);
+ first = false;
+ }
+ return ss.str();
+}
+
} //namespace
namespace tools
@@ -502,6 +528,7 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia
//----------------------------------------------------------------------------------------------------
bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_size_limit)
{
+ m_checkpoints.init_default_checkpoints(m_testnet);
if(m_http_client.is_connected())
m_http_client.disconnect();
m_is_initialized = true;
@@ -520,7 +547,7 @@ bool wallet2::is_deterministic() const
return keys_deterministic;
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::get_seed(std::string& electrum_words) const
+bool wallet2::get_seed(std::string& electrum_words, const std::string &passphrase) const
{
bool keys_deterministic = is_deterministic();
if (!keys_deterministic)
@@ -534,7 +561,10 @@ bool wallet2::get_seed(std::string& electrum_words) const
return false;
}
- crypto::ElectrumWords::bytes_to_words(get_account().get_keys().m_spend_secret_key, electrum_words, seed_language);
+ crypto::secret_key key = get_account().get_keys().m_spend_secret_key;
+ if (!passphrase.empty())
+ key = cryptonote::encrypt_key(key, passphrase);
+ crypto::ElectrumWords::bytes_to_words(key, electrum_words, seed_language);
return true;
}
@@ -577,24 +607,24 @@ void wallet2::set_unspent(size_t idx)
td.m_spent_height = 0;
}
//----------------------------------------------------------------------------------------------------
-void wallet2::check_acc_out_precomp(const crypto::public_key &spend_public_key, const tx_out &o, const crypto::key_derivation &derivation, size_t i, bool &received, uint64_t &money_transfered, bool &error) const
+void wallet2::check_acc_out_precomp(const crypto::public_key &spend_public_key, const tx_out &o, const crypto::key_derivation &derivation, size_t i, tx_scan_info_t &tx_scan_info) const
{
if (o.target.type() != typeid(txout_to_key))
{
- error = true;
+ tx_scan_info.error = true;
LOG_ERROR("wrong type id in transaction out");
return;
}
- received = is_out_to_acc_precomp(spend_public_key, boost::get<txout_to_key>(o.target), derivation, i);
- if(received)
+ tx_scan_info.received = is_out_to_acc_precomp(spend_public_key, boost::get<txout_to_key>(o.target), derivation, i);
+ if(tx_scan_info.received)
{
- money_transfered = o.amount; // may be 0 for ringct outputs
+ tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs
}
else
{
- money_transfered = 0;
+ tx_scan_info.money_transfered = 0;
}
- error = false;
+ tx_scan_info.error = false;
}
//----------------------------------------------------------------------------------------------------
static uint64_t decodeRct(const rct::rctSig & rv, const crypto::public_key &pub, const crypto::secret_key &sec, unsigned int i, rct::key & mask)
@@ -635,6 +665,22 @@ bool wallet2::wallet_generate_key_image_helper(const cryptonote::account_keys& a
return true;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::scan_output(const cryptonote::account_keys &keys, const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, uint64_t &tx_money_got_in_outs, std::vector<size_t> &outs)
+{
+ wallet_generate_key_image_helper(keys, tx_pub_key, i, tx_scan_info.in_ephemeral, tx_scan_info.ki);
+ THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
+ error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
+
+ outs.push_back(i);
+ if (tx_scan_info.money_transfered == 0)
+ {
+ tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_pub_key, keys.m_view_secret_key, i, tx_scan_info.mask);
+ }
+ tx_money_got_in_outs += tx_scan_info.money_transfered;
+ tx_scan_info.amount = tx_scan_info.money_transfered;
+ ++num_vouts_received;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool)
{
// In this function, tx (probably) only contains the base information
@@ -673,13 +719,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
int num_vouts_received = 0;
tx_pub_key = pub_key_field.pub_key;
bool r = true;
- std::deque<cryptonote::keypair> in_ephemeral(tx.vout.size());
- std::deque<crypto::key_image> ki(tx.vout.size());
- std::deque<uint64_t> amount(tx.vout.size());
- std::deque<rct::key> mask(tx.vout.size());
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
- int threads = tpool.get_max_concurrency();
+ std::unique_ptr<tx_scan_info_t[]> tx_scan_info{new tx_scan_info_t[tx.vout.size()]};
const cryptonote::account_keys& keys = m_account.get_keys();
crypto::key_derivation derivation;
generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
@@ -689,105 +731,64 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase)
{
- uint64_t money_transfered = 0;
- bool error = false, received = false;
- check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[0], derivation, 0, received, money_transfered, error);
- if (error)
+ check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[0], derivation, 0, tx_scan_info[0]);
+ if (tx_scan_info[0].error)
{
r = false;
}
else
{
// this assumes that the miner tx pays a single address
- if (received)
+ if (tx_scan_info[0].received)
{
- wallet_generate_key_image_helper(keys, tx_pub_key, 0, in_ephemeral[0], ki[0]);
- THROW_WALLET_EXCEPTION_IF(in_ephemeral[0].pub != boost::get<cryptonote::txout_to_key>(tx.vout[0].target).key,
- error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
-
- outs.push_back(0);
- if (money_transfered == 0)
- {
- money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, 0, mask[0]);
- }
- amount[0] = money_transfered;
- tx_money_got_in_outs = money_transfered;
- ++num_vouts_received;
+ scan_output(keys, tx, tx_pub_key, 0, tx_scan_info[0], num_vouts_received, tx_money_got_in_outs, outs);
// process the other outs from that tx
-
- std::vector<uint64_t> money_transfered(tx.vout.size());
- std::deque<bool> error(tx.vout.size());
- std::deque<bool> received(tx.vout.size());
// the first one was already checked
for (size_t i = 1; i < tx.vout.size(); ++i)
{
tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key), std::cref(tx.vout[i]), std::cref(derivation), i,
- std::ref(received[i]), std::ref(money_transfered[i]), std::ref(error[i])));
+ std::ref(tx_scan_info[i])));
}
waiter.wait();
+
for (size_t i = 1; i < tx.vout.size(); ++i)
{
- if (error[i])
+ if (tx_scan_info[i].error)
{
r = false;
break;
}
- if (received[i])
+ if (tx_scan_info[i].received)
{
- wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]);
- THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
- error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
-
- outs.push_back(i);
- if (money_transfered[i] == 0)
- {
- money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]);
- }
- tx_money_got_in_outs += money_transfered[i];
- amount[i] = money_transfered[i];
- ++num_vouts_received;
+ scan_output(keys, tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs);
}
}
}
}
}
- else if (tx.vout.size() > 1 && threads > 1)
+ else if (tx.vout.size() > 1 && tools::threadpool::getInstance().get_max_concurrency() > 1)
{
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
- std::vector<uint64_t> money_transfered(tx.vout.size());
- std::deque<bool> error(tx.vout.size());
- std::deque<bool> received(tx.vout.size());
for (size_t i = 0; i < tx.vout.size(); ++i)
{
- tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key), std::cref(tx.vout[i]), std::cref(derivation), i,
- std::ref(received[i]), std::ref(money_transfered[i]), std::ref(error[i])));
+ tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(keys.m_account_address.m_spend_public_key),
+ std::cref(tx.vout[i]), std::cref(derivation), i, std::ref(tx_scan_info[i])));
}
waiter.wait();
- tx_money_got_in_outs = 0;
+
for (size_t i = 0; i < tx.vout.size(); ++i)
{
- if (error[i])
+ if (tx_scan_info[i].error)
{
r = false;
break;
}
- if (received[i])
+ if (tx_scan_info[i].received)
{
- wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]);
- THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
- error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
-
- outs.push_back(i);
- if (money_transfered[i] == 0)
- {
- money_transfered[i] = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]);
- }
- tx_money_got_in_outs += money_transfered[i];
- amount[i] = money_transfered[i];
- ++num_vouts_received;
+ scan_output(keys, tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs);
}
}
}
@@ -795,31 +796,15 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{
for (size_t i = 0; i < tx.vout.size(); ++i)
{
- uint64_t money_transfered = 0;
- bool error = false, received = false;
- check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[i], derivation, i, received, money_transfered, error);
- if (error)
+ check_acc_out_precomp(keys.m_account_address.m_spend_public_key, tx.vout[i], derivation, i, tx_scan_info[i]);
+ if (tx_scan_info[i].error)
{
r = false;
break;
}
- else
+ if (tx_scan_info[i].received)
{
- if (received)
- {
- wallet_generate_key_image_helper(keys, tx_pub_key, i, in_ephemeral[i], ki[i]);
- THROW_WALLET_EXCEPTION_IF(in_ephemeral[i].pub != boost::get<cryptonote::txout_to_key>(tx.vout[i].target).key,
- error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key");
-
- outs.push_back(i);
- if (money_transfered == 0)
- {
- money_transfered = tools::decodeRct(tx.rct_signatures, pub_key_field.pub_key, keys.m_view_secret_key, i, mask[i]);
- }
- amount[i] = money_transfered;
- tx_money_got_in_outs += money_transfered;
- ++num_vouts_received;
- }
+ scan_output(keys, tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs);
}
}
}
@@ -841,7 +826,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
THROW_WALLET_EXCEPTION_IF(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" +
std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size()));
- auto kit = m_pub_keys.find(in_ephemeral[o].pub);
+ auto kit = m_pub_keys.find(tx_scan_info[o].in_ephemeral.pub);
THROW_WALLET_EXCEPTION_IF(kit != m_pub_keys.end() && kit->second >= m_transfers.size(),
error::wallet_internal_error, std::string("Unexpected transfer index from public key: ")
+ "got " + (kit == m_pub_keys.end() ? "<none>" : boost::lexical_cast<std::string>(kit->second))
@@ -857,14 +842,14 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_global_output_index = o_indices[o];
td.m_tx = (const cryptonote::transaction_prefix&)tx;
td.m_txid = txid;
- td.m_key_image = ki[o];
+ td.m_key_image = tx_scan_info[o].ki;
td.m_key_image_known = !m_watch_only;
td.m_amount = tx.vout[o].amount;
td.m_pk_index = pk_index - 1;
if (td.m_amount == 0)
{
- td.m_mask = mask[o];
- td.m_amount = amount[o];
+ td.m_mask = tx_scan_info[o].mask;
+ td.m_amount = tx_scan_info[o].amount;
td.m_rct = true;
}
else if (miner_tx && tx.version == 2)
@@ -879,7 +864,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
}
set_unspent(m_transfers.size()-1);
m_key_images[td.m_key_image] = m_transfers.size()-1;
- m_pub_keys[in_ephemeral[o].pub] = m_transfers.size()-1;
+ m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
if (0 != m_callback)
m_callback->on_money_received(height, txid, tx, td.m_amount);
@@ -912,8 +897,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_pk_index = pk_index - 1;
if (td.m_amount == 0)
{
- td.m_mask = mask[o];
- td.m_amount = amount[o];
+ td.m_mask = tx_scan_info[o].mask;
+ td.m_amount = tx_scan_info[o].amount;
td.m_rct = true;
}
else if (miner_tx && tx.version == 2)
@@ -926,7 +911,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity();
td.m_rct = false;
}
- THROW_WALLET_EXCEPTION_IF(td.get_public_key() != in_ephemeral[o].pub, error::wallet_internal_error, "Inconsistent public keys");
+ THROW_WALLET_EXCEPTION_IF(td.get_public_key() != tx_scan_info[o].in_ephemeral.pub, error::wallet_internal_error, "Inconsistent public keys");
THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status");
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
@@ -1128,16 +1113,19 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids) const
{
size_t i = 0;
size_t current_multiplier = 1;
- size_t sz = m_blockchain.size();
+ size_t sz = m_blockchain.size() - m_blockchain.offset();
if(!sz)
+ {
+ ids.push_back(m_blockchain.genesis());
return;
+ }
size_t current_back_offset = 1;
- bool genesis_included = false;
+ bool base_included = false;
while(current_back_offset < sz)
{
- ids.push_back(m_blockchain[sz-current_back_offset]);
+ ids.push_back(m_blockchain[m_blockchain.offset() + sz-current_back_offset]);
if(sz-current_back_offset == 0)
- genesis_included = true;
+ base_included = true;
if(i < 10)
{
++current_back_offset;
@@ -1147,8 +1135,10 @@ void wallet2::get_short_chain_history(std::list<crypto::hash>& ids) const
}
++i;
}
- if(!genesis_included)
- ids.push_back(m_blockchain[0]);
+ if(!base_included)
+ ids.push_back(m_blockchain[m_blockchain.offset()]);
+ if(m_blockchain.offset())
+ ids.push_back(m_blockchain.genesis());
}
//----------------------------------------------------------------------------------------------------
void wallet2::parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const
@@ -1233,6 +1223,7 @@ void wallet2::process_blocks(uint64_t start_height, const std::list<cryptonote::
size_t tx_o_indices_idx = 0;
THROW_WALLET_EXCEPTION_IF(blocks.size() != o_indices.size(), error::wallet_internal_error, "size mismatch");
+ THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::wallet_internal_error, "Index out of bounds of hashchain");
tools::threadpool& tpool = tools::threadpool::getInstance();
int threads = tpool.get_max_concurrency();
@@ -1529,23 +1520,22 @@ void wallet2::update_pool_state(bool refreshed)
{
if (res.txs.size() == txids.size())
{
- size_t n = 0;
- for (const auto &txid: txids)
+ for (const auto &tx_entry: res.txs)
{
- // might have just been put in a block
- if (res.txs[n].in_pool)
+ if (tx_entry.in_pool)
{
cryptonote::transaction tx;
cryptonote::blobdata bd;
crypto::hash tx_hash, tx_prefix_hash;
- if (epee::string_tools::parse_hexstr_to_binbuff(res.txs[n].as_hex, bd))
+ if (epee::string_tools::parse_hexstr_to_binbuff(tx_entry.as_hex, bd))
{
if (cryptonote::parse_and_validate_tx_from_blob(bd, tx, tx_hash, tx_prefix_hash))
{
- if (tx_hash == txid)
+ const std::vector<crypto::hash>::const_iterator i = std::find(txids.begin(), txids.end(), tx_hash);
+ if (i != txids.end())
{
- process_new_transaction(txid, tx, std::vector<uint64_t>(), 0, time(NULL), false, true);
- m_scanned_pool_txs[0].insert(txid);
+ process_new_transaction(tx_hash, tx, std::vector<uint64_t>(), 0, time(NULL), false, true);
+ m_scanned_pool_txs[0].insert(tx_hash);
if (m_scanned_pool_txs[0].size() > 5000)
{
std::swap(m_scanned_pool_txs[0], m_scanned_pool_txs[1]);
@@ -1554,7 +1544,7 @@ void wallet2::update_pool_state(bool refreshed)
}
else
{
- LOG_PRINT_L0("Mismatched txids when processing unconfimed txes from pool");
+ MERROR("Got txid " << tx_hash << " which we did not ask for");
}
}
else
@@ -1564,14 +1554,13 @@ void wallet2::update_pool_state(bool refreshed)
}
else
{
- LOG_PRINT_L0("Failed to parse tx " << txid);
+ LOG_PRINT_L0("Failed to parse transaction from daemon");
}
}
else
{
- LOG_PRINT_L1("Tx " << txid << " was in pool, but is no more");
+ LOG_PRINT_L1("Transaction from daemon was in pool, but is no more");
}
- ++n;
}
}
else
@@ -1787,6 +1776,13 @@ bool wallet2::refresh(uint64_t & blocks_fetched, bool& received_money, bool& ok)
void wallet2::detach_blockchain(uint64_t height)
{
LOG_PRINT_L0("Detaching blockchain on height " << height);
+
+ // size 1 2 3 4 5 6 7 8 9
+ // block 0 1 2 3 4 5 6 7 8
+ // C
+ THROW_WALLET_EXCEPTION_IF(height <= m_checkpoints.get_max_height() && m_blockchain.size() > m_checkpoints.get_max_height(),
+ error::wallet_internal_error, "Daemon claims reorg below last checkpoint");
+
size_t transfers_detached = 0;
for (size_t i = 0; i < m_transfers.size(); ++i)
@@ -1817,8 +1813,8 @@ void wallet2::detach_blockchain(uint64_t height)
}
m_transfers.erase(it, m_transfers.end());
- size_t blocks_detached = m_blockchain.end() - (m_blockchain.begin()+height);
- m_blockchain.erase(m_blockchain.begin()+height, m_blockchain.end());
+ size_t blocks_detached = m_blockchain.size() - height;
+ m_blockchain.crop(height);
m_local_bc_height -= blocks_detached;
for (auto it = m_payments.begin(); it != m_payments.end(); )
@@ -2562,13 +2558,49 @@ void wallet2::load(const std::string& wallet_, const std::string& password)
check_genesis(genesis_hash);
}
+ trim_hashchain();
+
m_local_bc_height = m_blockchain.size();
}
//----------------------------------------------------------------------------------------------------
+void wallet2::trim_hashchain()
+{
+ uint64_t height = m_checkpoints.get_max_height();
+ if (!m_blockchain.empty() && m_blockchain.size() == m_blockchain.offset())
+ {
+ MINFO("Fixing empty hashchain");
+ epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request> req = AUTO_VAL_INIT(req);
+ epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response, std::string> res = AUTO_VAL_INIT(res);
+ m_daemon_rpc_mutex.lock();
+ req.jsonrpc = "2.0";
+ req.id = epee::serialization::storage_entry(0);
+ req.method = "getblockheaderbyheight";
+ req.params.height = m_blockchain.size() - 1;
+ bool r = net_utils::invoke_http_json("/json_rpc", req, res, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+ if (r && res.result.status == CORE_RPC_STATUS_OK)
+ {
+ crypto::hash hash;
+ epee::string_tools::hex_to_pod(res.result.block_header.hash, hash);
+ m_blockchain.refill(hash);
+ }
+ else
+ {
+ MERROR("Failed to request block header from daemon, hash chain may be unable to sync till the wallet is loaded with a usable daemon");
+ }
+ }
+ if (height > 0 && m_blockchain.size() > height)
+ {
+ --height;
+ MDEBUG("trimming to " << height << ", offset " << m_blockchain.offset());
+ m_blockchain.trim(height);
+ }
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::check_genesis(const crypto::hash& genesis_hash) const {
std::string what("Genesis block mismatch. You probably use wallet without testnet flag with blockchain from test network or vice versa");
- THROW_WALLET_EXCEPTION_IF(genesis_hash != m_blockchain[0], error::wallet_internal_error, what);
+ THROW_WALLET_EXCEPTION_IF(genesis_hash != m_blockchain.genesis(), error::wallet_internal_error, what);
}
//----------------------------------------------------------------------------------------------------
std::string wallet2::path() const
@@ -2583,6 +2615,8 @@ void wallet2::store()
//----------------------------------------------------------------------------------------------------
void wallet2::store_to(const std::string &path, const std::string &password)
{
+ trim_hashchain();
+
// if file is the same, we do:
// 1. save wallet to the *.new file
// 2. remove old wallet file
@@ -2645,10 +2679,11 @@ void wallet2::store_to(const std::string &path, const std::string &password)
// if we here, main wallet file is saved and we only need to save keys and address files
if (!same_file) {
prepare_file_names(path);
- store_keys(m_keys_file, password, false);
+ bool r = store_keys(m_keys_file, password, false);
+ THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
// save address to the new file
const std::string address_file = m_wallet_file + ".address.txt";
- bool r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet));
+ r = file_io_utils::save_string_to_file(address_file, m_account.get_public_address_str(m_testnet));
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_wallet_file);
// remove old wallet file
r = boost::filesystem::remove(old_file);
@@ -3090,7 +3125,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
{
std::vector<tx_extra_field> tx_extra_fields;
if(!parse_tx_extra(ptx.tx.extra, tx_extra_fields))
- return cryptonote::null_hash;
+ return crypto::null_hash;
tx_extra_nonce extra_nonce;
crypto::hash payment_id = null_hash;
if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
@@ -3105,7 +3140,7 @@ crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
}
else if (!get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
{
- payment_id = cryptonote::null_hash;
+ payment_id = crypto::null_hash;
}
}
return payment_id;
@@ -3154,7 +3189,7 @@ void wallet2::commit_tx(pending_tx& ptx)
}
txid = get_transaction_hash(ptx.tx);
- crypto::hash payment_id = cryptonote::null_hash;
+ crypto::hash payment_id = crypto::null_hash;
std::vector<cryptonote::tx_destination_entry> dests;
uint64_t amount_in = 0;
if (store_tx_info())
@@ -4338,7 +4373,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
else
{
- THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error, "original_output_index too large");
+ THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error,
+ std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size()));
if (original_output_index == dsts.size())
dsts.push_back(tx_destination_entry(0,addr));
THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &addr, sizeof(addr)), error::wallet_internal_error, "Mismatched destination address");
@@ -4437,12 +4473,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
TX &tx = txes.back();
LOG_PRINT_L2("Start of loop with " << unused_transfers_indices.size() << " " << unused_dust_indices.size());
- LOG_PRINT_L2("unused_transfers_indices:");
- for (auto t: unused_transfers_indices)
- LOG_PRINT_L2(" " << t);
- LOG_PRINT_L2("unused_dust_indices:");
- for (auto t: unused_dust_indices)
- LOG_PRINT_L2(" " << t);
+ LOG_PRINT_L2("unused_transfers_indices: " << strjoin(unused_transfers_indices, " "));
+ LOG_PRINT_L2("unused_dust_indices:" << strjoin(unused_dust_indices, " "));
LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? -1 : dsts[0].amount));
LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct);
@@ -4616,6 +4648,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
{
LOG_PRINT_L2("We have more to pay, starting another tx");
txes.push_back(TX());
+ original_output_index = 0;
}
}
}
@@ -5164,10 +5197,9 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
for (size_t i = 0; i < td.m_tx.vout.size(); ++i)
{
- uint64_t money_transfered = 0;
- bool error = false, received = false;
- check_acc_out_precomp(keys.m_account_address.m_spend_public_key, td.m_tx.vout[i], derivation, i, received, money_transfered, error);
- if (!error && received)
+ tx_scan_info_t tx_scan_info;
+ check_acc_out_precomp(keys.m_account_address.m_spend_public_key, td.m_tx.vout[i], derivation, i, tx_scan_info);
+ if (!tx_scan_info.error && tx_scan_info.received)
return tx_pub_key;
}
}
@@ -5175,7 +5207,7 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
// we found no key yielding an output
THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error,
"Public key yielding at least one output wasn't found in the transaction extra");
- return cryptonote::null_pkey;
+ return crypto::null_pkey;
}
bool wallet2::export_key_images(const std::string filename)
@@ -5381,6 +5413,9 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
}
spent = 0;
unspent = 0;
+ std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input.
+ std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
+ // was created by sweep_all, so we can't know the spent height and other detailed info.
for(size_t i = 0; i < m_transfers.size(); ++i)
{
transfer_details &td = m_transfers[i];
@@ -5391,8 +5426,145 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
unspent += amount;
LOG_PRINT_L2("Transfer " << i << ": " << print_money(amount) << " (" << td.m_global_output_index << "): "
<< (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[i] << ")");
+
+ if (i < daemon_resp.spent_status.size() && daemon_resp.spent_status[i] == COMMAND_RPC_IS_KEY_IMAGE_SPENT::SPENT_IN_BLOCKCHAIN)
+ {
+ bool is_spent_tx_found = false;
+ for (auto it = m_transfers.rbegin(); &(*it) != &td; ++it)
+ {
+ bool is_spent_tx = false;
+ for(const cryptonote::txin_v& in : it->m_tx.vin)
+ {
+ if(in.type() == typeid(cryptonote::txin_to_key) && td.m_key_image == boost::get<cryptonote::txin_to_key>(in).k_image)
+ {
+ is_spent_tx = true;
+ break;
+ }
+ }
+ if (is_spent_tx)
+ {
+ is_spent_tx_found = true;
+ spent_txids.insert(it->m_txid);
+ break;
+ }
+ }
+
+ if (!is_spent_tx_found)
+ swept_transfers.push_back(i);
+ }
}
MDEBUG("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent");
+
+ if (check_spent)
+ {
+ // query outgoing txes
+ COMMAND_RPC_GET_TRANSACTIONS::request gettxs_req;
+ COMMAND_RPC_GET_TRANSACTIONS::response gettxs_res;
+ gettxs_req.decode_as_json = false;
+ for (const crypto::hash& spent_txid : spent_txids)
+ gettxs_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(spent_txid));
+ m_daemon_rpc_mutex.lock();
+ bool r = epee::net_utils::invoke_http_json("/gettransactions", gettxs_req, gettxs_res, m_http_client, 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");
+ THROW_WALLET_EXCEPTION_IF(gettxs_res.txs.size() != spent_txids.size(), error::wallet_internal_error,
+ "daemon returned wrong response for gettransactions, wrong count = " + std::to_string(gettxs_res.txs.size()) + ", expected " + std::to_string(spent_txids.size()));
+
+ // process each outgoing tx
+ auto spent_txid = spent_txids.begin();
+ for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs)
+ {
+ THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool");
+
+ // parse tx
+ cryptonote::blobdata bd;
+ THROW_WALLET_EXCEPTION_IF(!epee::string_tools::parse_hexstr_to_binbuff(e.as_hex, bd), error::wallet_internal_error, "parse_hexstr_to_binbuff failed");
+ cryptonote::transaction spent_tx;
+ crypto::hash spnet_txid_parsed, spent_txid_prefix;
+ THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(bd, spent_tx, spnet_txid_parsed, spent_txid_prefix), error::wallet_internal_error, "parse_and_validate_tx_from_blob failed");
+ THROW_WALLET_EXCEPTION_IF(*spent_txid != spnet_txid_parsed, error::wallet_internal_error, "parsed txid mismatch");
+
+ // get received (change) amount
+ uint64_t tx_money_got_in_outs = 0;
+ const cryptonote::account_keys& keys = m_account.get_keys();
+ const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(spent_tx);
+ crypto::key_derivation derivation;
+ generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation);
+ size_t output_index = 0;
+ for (const cryptonote::tx_out& out : spent_tx.vout)
+ {
+ tx_scan_info_t tx_scan_info;
+ check_acc_out_precomp(keys.m_account_address.m_spend_public_key, out, derivation, output_index, tx_scan_info);
+ THROW_WALLET_EXCEPTION_IF(tx_scan_info.error, error::wallet_internal_error, "check_acc_out_precomp failed");
+ if (tx_scan_info.received)
+ {
+ if (tx_scan_info.money_transfered == 0)
+ {
+ rct::key mask;
+ tx_scan_info.money_transfered = tools::decodeRct(spent_tx.rct_signatures, tx_pub_key, keys.m_view_secret_key, output_index, mask);
+ }
+ tx_money_got_in_outs += tx_scan_info.money_transfered;
+ }
+ ++output_index;
+ }
+
+ // get spent amount
+ uint64_t tx_money_spent_in_ins = 0;
+ for (const cryptonote::txin_v& in : spent_tx.vin)
+ {
+ if (in.type() != typeid(cryptonote::txin_to_key))
+ continue;
+ auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image);
+ if (it != m_key_images.end())
+ {
+ const transfer_details& td = m_transfers[it->second];
+ uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount;
+ if (amount > 0)
+ {
+ THROW_WALLET_EXCEPTION_IF(amount != td.amount(), error::wallet_internal_error,
+ std::string("Inconsistent amount in tx input: got ") + print_money(amount) +
+ std::string(", expected ") + print_money(td.amount()));
+ }
+ amount = td.amount();
+ tx_money_spent_in_ins += amount;
+
+ LOG_PRINT_L0("Spent money: " << print_money(amount) << ", with tx: " << *spent_txid);
+ set_spent(it->second, e.block_height);
+ if (m_callback)
+ m_callback->on_money_spent(e.block_height, *spent_txid, spent_tx, amount, spent_tx);
+ }
+ }
+
+ // create outgoing payment
+ process_outgoing(*spent_txid, spent_tx, e.block_height, e.block_timestamp, tx_money_spent_in_ins, tx_money_got_in_outs);
+
+ // erase corresponding incoming payment
+ for (auto j = m_payments.begin(); j != m_payments.end(); ++j)
+ {
+ if (j->second.m_tx_hash == *spent_txid)
+ {
+ m_payments.erase(j);
+ break;
+ }
+ }
+
+ ++spent_txid;
+ }
+
+ for (size_t n : swept_transfers)
+ {
+ const transfer_details& td = m_transfers[n];
+ confirmed_transfer_details pd;
+ pd.m_change = (uint64_t)-1; // cahnge is unknown
+ pd.m_amount_in = pd.m_amount_out = td.amount(); // fee is unknown
+ std::string err;
+ pd.m_block_height = get_daemon_blockchain_height(err); // spent block height is unknown, so hypothetically set to the highest
+ crypto::hash spent_txid = crypto::rand<crypto::hash>(); // spent txid is unknown, so hypothetically set to random
+ m_confirmed_txs.insert(std::make_pair(spent_txid, pd));
+ }
+ }
+
return m_transfers[signed_key_images.size() - 1].m_block_height;
}
wallet2::payment_container wallet2::export_payments() const
@@ -5421,20 +5593,28 @@ void wallet2::import_payments_out(const std::list<std::pair<crypto::hash,wallet2
}
}
-std::vector<crypto::hash> wallet2::export_blockchain() const
+std::tuple<size_t,crypto::hash,std::vector<crypto::hash>> wallet2::export_blockchain() const
{
- std::vector<crypto::hash> bc;
- for (auto const &b : m_blockchain)
+ std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> bc;
+ std::get<0>(bc) = m_blockchain.offset();
+ std::get<1>(bc) = m_blockchain.empty() ? crypto::null_hash: m_blockchain.genesis();
+ for (size_t n = m_blockchain.offset(); n < m_blockchain.size(); ++n)
{
- bc.push_back(b);
+ std::get<2>(bc).push_back(m_blockchain[n]);
}
return bc;
}
-void wallet2::import_blockchain(const std::vector<crypto::hash> &bc)
+void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc)
{
m_blockchain.clear();
- for (auto const &b : bc)
+ if (std::get<0>(bc))
+ {
+ for (size_t n = std::get<0>(bc); n > 0; ++n)
+ m_blockchain.push_back(std::get<1>(bc));
+ m_blockchain.trim(std::get<0>(bc));
+ }
+ for (auto const &b : std::get<2>(bc))
{
m_blockchain.push_back(b);
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index adf03abcc..1dff14a95 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -36,6 +36,7 @@
#include <boost/program_options/variables_map.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
+#include <boost/serialization/deque.hpp>
#include <atomic>
#include "include_base_utils.h"
@@ -52,6 +53,7 @@
#include "crypto/hash.h"
#include "ringct/rctTypes.h"
#include "ringct/rctOps.h"
+#include "checkpoints/checkpoints.h"
#include "wallet_errors.h"
#include "common/password.h"
@@ -91,6 +93,38 @@ namespace tools
}
};
+ class hashchain
+ {
+ public:
+ hashchain(): m_genesis(crypto::null_hash), m_offset(0) {}
+
+ size_t size() const { return m_blockchain.size() + m_offset; }
+ size_t offset() const { return m_offset; }
+ const crypto::hash &genesis() const { return m_genesis; }
+ void push_back(const crypto::hash &hash) { if (m_offset == 0 && m_blockchain.empty()) m_genesis = hash; m_blockchain.push_back(hash); }
+ bool is_in_bounds(size_t idx) const { return idx >= m_offset && idx < size(); }
+ const crypto::hash &operator[](size_t idx) const { return m_blockchain[idx - m_offset]; }
+ crypto::hash &operator[](size_t idx) { return m_blockchain[idx - m_offset]; }
+ void crop(size_t height) { m_blockchain.resize(height - m_offset); }
+ void clear() { m_offset = 0; m_blockchain.clear(); }
+ bool empty() const { return m_blockchain.empty() && m_offset == 0; }
+ void trim(size_t height) { while (height > m_offset+1 && m_blockchain.size() > 1) { m_blockchain.pop_front(); ++m_offset; } m_blockchain.shrink_to_fit(); }
+ void refill(const crypto::hash &hash) { m_blockchain.push_back(hash); --m_offset; }
+
+ template <class t_archive>
+ inline void serialize(t_archive &a, const unsigned int ver)
+ {
+ a & m_offset;
+ a & m_genesis;
+ a & m_blockchain;
+ }
+
+ private:
+ size_t m_offset;
+ crypto::hash m_genesis;
+ std::deque<crypto::hash> m_blockchain;
+ };
+
class wallet2
{
friend class ::Serialization_portability_wallet_Test;
@@ -133,6 +167,19 @@ namespace tools
wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_confirm_backlog(true), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
+ struct tx_scan_info_t
+ {
+ cryptonote::keypair in_ephemeral;
+ crypto::key_image ki;
+ rct::key mask;
+ uint64_t amount;
+ uint64_t money_transfered;
+ bool error;
+ bool received;
+
+ tx_scan_info_t(): money_transfered(0), error(true), received(false) {}
+ };
+
struct transfer_details
{
uint64_t m_block_height;
@@ -203,7 +250,7 @@ namespace tools
uint64_t m_timestamp;
uint64_t m_unlock_time;
- confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(cryptonote::null_hash), m_timestamp(0), m_unlock_time(0) {}
+ confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_block_height(0), m_payment_id(crypto::null_hash), m_timestamp(0), m_unlock_time(0) {}
confirmed_transfer_details(const unconfirmed_transfer_details &utd, uint64_t height):
m_amount_in(utd.m_amount_in), m_amount_out(utd.m_amount_out), m_change(utd.m_change), m_block_height(height), m_dests(utd.m_dests), m_payment_id(utd.m_payment_id), m_timestamp(utd.m_timestamp), m_unlock_time(utd.m_tx.unlock_time) {}
};
@@ -363,7 +410,7 @@ namespace tools
* \brief Checks if deterministic wallet
*/
bool is_deterministic() const;
- bool get_seed(std::string& electrum_words) const;
+ bool get_seed(std::string& electrum_words, const std::string &passphrase = std::string()) const;
/*!
* \brief Gets the seed language
*/
@@ -439,7 +486,19 @@ namespace tools
uint64_t dummy_refresh_height = 0; // moved to keys file
if(ver < 5)
return;
- a & m_blockchain;
+ if (ver < 19)
+ {
+ std::vector<crypto::hash> blockchain;
+ a & blockchain;
+ for (const auto &b: blockchain)
+ {
+ m_blockchain.push_back(b);
+ }
+ }
+ else
+ {
+ a & m_blockchain;
+ }
a & m_transfers;
a & m_account_public_address;
a & m_key_images;
@@ -588,8 +647,8 @@ namespace tools
payment_container export_payments() const;
void import_payments(const payment_container &payments);
void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments);
- std::vector<crypto::hash> export_blockchain() const;
- void import_blockchain(const std::vector<crypto::hash> &bc);
+ std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
+ void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
bool export_key_images(const std::string filename);
std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const;
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
@@ -650,7 +709,7 @@ namespace tools
bool generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const;
crypto::hash get_payment_id(const pending_tx &ptx) const;
crypto::hash8 get_short_payment_id(const pending_tx &ptx) const;
- void check_acc_out_precomp(const crypto::public_key &spend_public_key, const cryptonote::tx_out &o, const crypto::key_derivation &derivation, size_t i, bool &received, uint64_t &money_transfered, bool &error) const;
+ void check_acc_out_precomp(const crypto::public_key &spend_public_key, const cryptonote::tx_out &o, const crypto::key_derivation &derivation, size_t i, tx_scan_info_t &tx_scan_info) const;
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
uint64_t get_upper_transaction_size_limit();
std::vector<uint64_t> get_unspent_amounts_vector();
@@ -664,6 +723,8 @@ namespace tools
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
std::vector<size_t> get_only_rct(const std::vector<size_t> &unused_dust_indices, const std::vector<size_t> &unused_transfers_indices) const;
+ void scan_output(const cryptonote::account_keys &keys, const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, uint64_t &tx_money_got_in_outs, std::vector<size_t> &outs);
+ void trim_hashchain();
cryptonote::account_base m_account;
boost::optional<epee::net_utils::http::login> m_daemon_login;
@@ -671,12 +732,13 @@ namespace tools
std::string m_wallet_file;
std::string m_keys_file;
epee::net_utils::http::http_simple_client m_http_client;
- std::vector<crypto::hash> m_blockchain;
+ hashchain m_blockchain;
std::atomic<uint64_t> m_local_bc_height; //temporary workaround
std::unordered_map<crypto::hash, unconfirmed_transfer_details> m_unconfirmed_txs;
std::unordered_map<crypto::hash, confirmed_transfer_details> m_confirmed_txs;
std::unordered_multimap<crypto::hash, payment_details> m_unconfirmed_payments;
std::unordered_map<crypto::hash, crypto::secret_key> m_tx_keys;
+ cryptonote::checkpoints m_checkpoints;
transfer_container m_transfers;
payment_container m_payments;
@@ -716,7 +778,7 @@ namespace tools
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 18)
+BOOST_CLASS_VERSION(tools::wallet2, 19)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h
index 8da8c62eb..7a5e01af7 100644
--- a/src/wallet/wallet2_api.h
+++ b/src/wallet/wallet2_api.h
@@ -663,7 +663,7 @@ struct WalletManager
* \param wallet previously opened / created wallet instance
* \return None
*/
- virtual bool closeWallet(Wallet *wallet) = 0;
+ virtual bool closeWallet(Wallet *wallet, bool store = true) = 0;
/*
* ! checks if wallet with the given name already exists
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
index 81dc7e549..22cfcc269 100644
--- a/src/wallet/wallet_args.cpp
+++ b/src/wallet/wallet_args.cpp
@@ -84,6 +84,7 @@ namespace wallet_args
#endif
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
+ const command_line::arg_descriptor<std::size_t> arg_max_log_file_size = {"max-log-file-size", "Specify maximum log file size [B]", MAX_LOG_FILE_SIZE};
const command_line::arg_descriptor<uint32_t> arg_max_concurrency = {"max-concurrency", wallet_args::tr("Max number of threads to use for a parallel job"), DEFAULT_MAX_CONCURRENCY};
const command_line::arg_descriptor<std::string> arg_log_file = {"log-file", wallet_args::tr("Specify log file"), ""};
const command_line::arg_descriptor<std::string> arg_config_file = {"config-file", wallet_args::tr("Config file"), "", true};
@@ -99,8 +100,9 @@ namespace wallet_args
command_line::add_arg(desc_general, command_line::arg_help);
command_line::add_arg(desc_general, command_line::arg_version);
- command_line::add_arg(desc_params, arg_log_file, "");
+ command_line::add_arg(desc_params, arg_log_file);
command_line::add_arg(desc_params, arg_log_level);
+ command_line::add_arg(desc_params, arg_max_log_file_size);
command_line::add_arg(desc_params, arg_max_concurrency);
command_line::add_arg(desc_params, arg_config_file);
@@ -156,7 +158,7 @@ namespace wallet_args
log_path = command_line::get_arg(vm, arg_log_file);
else
log_path = mlog_get_default_log_path(default_log_name);
- mlog_configure(log_path, log_to_console);
+ mlog_configure(log_path, log_to_console, command_line::get_arg(vm, arg_max_log_file_size));
if (!vm["log-level"].defaulted())
{
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 773d12775..46b092376 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+#include <boost/format.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/filesystem/operations.hpp>
#include <cstdint>
@@ -37,7 +38,6 @@ using namespace epee;
#include "wallet/wallet_args.h"
#include "common/command_line.h"
#include "common/i18n.h"
-#include "common/util.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_basic/account.h"
#include "wallet_rpc_server_commands_defs.h"
@@ -70,18 +70,12 @@ namespace tools
}
//------------------------------------------------------------------------------------------------------------------------------
- wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_filename(), m_stop(false), m_trusted_daemon(false)
+ wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_file(), m_stop(false), m_trusted_daemon(false), m_vm(NULL)
{
}
//------------------------------------------------------------------------------------------------------------------------------
wallet_rpc_server::~wallet_rpc_server()
{
- try
- {
- boost::system::error_code ec{};
- boost::filesystem::remove(rpc_login_filename, ec);
- }
- catch (...) {}
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::set_wallet(wallet2 *cr)
@@ -160,7 +154,15 @@ namespace tools
#else
#define MKDIR(path, mode) mkdir(path, mode)
#endif
- MKDIR(m_wallet_dir.c_str(), 0700);
+ if (MKDIR(m_wallet_dir.c_str(), 0700) < 0)
+ {
+#ifdef _WIN32
+ LOG_ERROR(tr("Failed to create directory ") + m_wallet_dir);
+#else
+ LOG_ERROR((boost::format(tr("Failed to create directory %s: %s")) % m_wallet_dir % strerror(errno)).str());
+#endif
+ return false;
+ }
}
if (disable_auth)
@@ -182,34 +184,32 @@ namespace tools
default_rpc_username,
string_encoding::base64_encode(rand_128bit.data(), rand_128bit.size())
);
+
+ std::string temp = "monero-wallet-rpc." + bind_port + ".login";
+ rpc_login_file = tools::private_file::create(temp);
+ if (!rpc_login_file.handle())
+ {
+ LOG_ERROR(tr("Failed to create file ") << temp << tr(". Check permissions or remove file"));
+ return false;
+ }
+ std::fputs(http_login->username.c_str(), rpc_login_file.handle());
+ std::fputc(':', rpc_login_file.handle());
+ std::fputs(http_login->password.c_str(), rpc_login_file.handle());
+ std::fflush(rpc_login_file.handle());
+ if (std::ferror(rpc_login_file.handle()))
+ {
+ LOG_ERROR(tr("Error writing to file ") << temp);
+ return false;
+ }
+ LOG_PRINT_L0(tr("RPC username/password is stored in file ") << temp);
}
- else
+ else // chosen user/pass
{
http_login.emplace(
std::move(rpc_config->login->username), std::move(rpc_config->login->password).password()
);
}
assert(bool(http_login));
-
- std::string temp = "monero-wallet-rpc." + bind_port + ".login";
- const auto cookie = tools::create_private_file(temp);
- if (!cookie)
- {
- LOG_ERROR(tr("Failed to create file ") << temp << tr(". Check permissions or remove file"));
- return false;
- }
- rpc_login_filename.swap(temp); // nothrow guarantee destructor cleanup
- temp = rpc_login_filename;
- std::fputs(http_login->username.c_str(), cookie.get());
- std::fputc(':', cookie.get());
- std::fputs(http_login->password.c_str(), cookie.get());
- std::fflush(cookie.get());
- if (std::ferror(cookie.get()))
- {
- LOG_ERROR(tr("Error writing to file ") << temp);
- return false;
- }
- LOG_PRINT_L0(tr("RPC username/password is stored in file ") << temp);
} // end auth enabled
m_http_client.set_server(walvars->get_daemon_address(), walvars->get_daemon_login());
@@ -362,7 +362,7 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::validate_transfer(const std::list<wallet_rpc::transfer_destination> destinations, std::string payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, epee::json_rpc::error& er)
{
- crypto::hash8 integrated_payment_id = cryptonote::null_hash8;
+ crypto::hash8 integrated_payment_id = crypto::null_hash8;
std::string extra_nonce;
for (auto it = destinations.begin(); it != destinations.end(); it++)
{
@@ -395,7 +395,7 @@ namespace tools
if (has_payment_id)
{
- if (!payment_id.empty() || integrated_payment_id != cryptonote::null_hash8)
+ if (!payment_id.empty() || integrated_payment_id != crypto::null_hash8)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
er.message = "A single payment id is allowed per transaction";
@@ -1485,7 +1485,7 @@ namespace tools
cryptonote::account_public_address address;
bool has_payment_id;
crypto::hash8 payment_id8;
- crypto::hash payment_id = cryptonote::null_hash;
+ crypto::hash payment_id = crypto::null_hash;
er.message = "";
if(!get_account_address_from_str_or_url(address, has_payment_id, payment_id8, m_wallet->testnet(), req.address,
[&er](const std::string &url, const std::vector<std::string> &addresses, bool dnssec_valid)->std::string {
@@ -1545,7 +1545,7 @@ namespace tools
er.message = "Failed to add address book entry";
return false;
}
- res.index = m_wallet->get_address_book().size();
+ res.index = m_wallet->get_address_book().size() - 1;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -1896,7 +1896,15 @@ just_dir:
wrpc.send_stop_signal();
});
LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet rpc server"));
- wrpc.run();
+ try
+ {
+ wrpc.run();
+ }
+ catch (const std::exception &e)
+ {
+ LOG_ERROR(tools::wallet_rpc_server::tr("Failed to run wallet: ") << e.what());
+ return 1;
+ }
LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet rpc server"));
try
{
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index dd54222b0..e5ed0a846 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -33,6 +33,7 @@
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <string>
+#include "common/util.h"
#include "net/http_server_impl_base.h"
#include "wallet_rpc_server_commands_defs.h"
#include "wallet2.h"
@@ -154,7 +155,7 @@ namespace tools
wallet2 *m_wallet;
std::string m_wallet_dir;
- std::string rpc_login_filename;
+ tools::private_file rpc_login_file;
std::atomic<bool> m_stop;
bool m_trusted_daemon;
epee::net_utils::http::http_simple_client m_http_client;